From 579ea8b0364c9aca1a9becab1fe5511ed1b723bf Mon Sep 17 00:00:00 2001 From: EWSoftware Date: Thu, 9 Jan 2025 14:34:47 -0800 Subject: [PATCH] .NET 8 and nullable reference types support --- .editorconfig | 76 +- Doc/Content/VersionHistory/VersionHistory.aml | 5 + Doc/Content/VersionHistory/v2025.1.9.0.aml | 33 + Doc/ContentLayout.content | 7 +- Doc/EWSoftwarePDI.shfbproj | 5 +- IgnoredWords.dic | 10 + MasterBuild.bat | 6 - .../CSharpDemos/CalendarBrowser/AboutDlg.cs | 21 +- .../CalendarBrowser/AlarmControl.cs | 29 +- .../CalendarBrowser/AttachmentsControl.cs | 98 ++- .../CalendarBrowser/AttendeeControl.cs | 17 +- .../CalendarBrowser/CalendarBrowser.csproj | 50 +- .../CalendarBrowser/CalendarBrowserForm.cs | 291 ++++---- .../CalendarBrowser/CalendarObjectDlg.cs | 34 +- .../CalendarBrowser/FreeBusyControl.cs | 33 +- .../CalendarBrowser/GlobalSuppressions.cs | Bin 16822 -> 17290 bytes .../CalendarBrowser/ObservanceRuleControl.cs | 27 +- .../Properties/AssemblyInfoShared.cs | 12 +- .../CalendarBrowser/RecurrenceControl.cs | 80 +-- .../CalendarBrowser/RequestStatusControl.cs | 7 +- .../CalendarBrowser/TimeZoneListDlg.cs | 64 +- .../CalendarBrowser/VFreeBusyDlg.cs | 16 +- .../CalendarBrowser/VTimeZoneDlg.cs | 8 +- Source/CSharpDemos/CalendarBrowser/app.config | 3 - .../CSharpDemos/CalendarBrowser/app.manifest | 36 - .../CSharpDemos/PDIDatesTest/PDIDatesTest.cs | 48 +- .../PDIDatesTest/PDIDatesTest.csproj | 50 +- .../PDIParserTest/PDIParserTest.cs | 19 +- .../PDIParserTest/PDIParserTest.csproj | 46 +- Source/CSharpDemos/PDIWebDemoCS/Web.config | 2 +- .../CSharpDemos/PDIWinFormsTest/AboutDlg.cs | 17 +- .../PDIWinFormsTest/EventRecurTestForm.cs | 14 +- .../PDIWinFormsTest/HolidayTestForm.cs | 16 +- .../CSharpDemos/PDIWinFormsTest/MainForm.cs | 40 +- .../PDIWinFormsTest/PDIWinFormsTest.csproj | 50 +- .../PDIWinFormsTest/RRuleTestForm.cs | 41 +- .../PDIWinFormsTest/TimeZoneRegInfo.cs | 150 ++-- .../PDIWinFormsTest/VTimeZoneTestForm.cs | 86 ++- Source/CSharpDemos/PDIWinFormsTest/app.config | 3 - .../CSharpDemos/PDIWinFormsTest/app.manifest | 32 - .../RFC2445RecurTest/RFC2445RecurTest.cs | 113 +-- .../RFC2445RecurTest/RFC2445RecurTest.csproj | 46 +- Source/CSharpDemos/vCardBrowser/AboutDlg.cs | 23 +- .../vCardBrowser/AddressControl.cs | 41 +- .../CSharpDemos/vCardBrowser/EMailControl.cs | 28 +- .../CSharpDemos/vCardBrowser/LabelControl.cs | 32 +- .../CSharpDemos/vCardBrowser/PhoneControl.cs | 34 +- .../CSharpDemos/vCardBrowser/PhotoControl.cs | 93 ++- .../vCardBrowser/VCardBrowserForm.Designer.cs | 7 +- .../vCardBrowser/VCardBrowserForm.cs | 218 +++--- .../vCardBrowser/VCardPropertiesDlg.cs | 25 +- Source/CSharpDemos/vCardBrowser/app.config | 3 - Source/CSharpDemos/vCardBrowser/app.manifest | 36 - .../vCardBrowser/vCardBrowser.csproj | 56 +- Source/EWSPDI/DailyFrequency.cs | 13 +- Source/EWSPDI/DateUtils.cs | 17 +- Source/EWSPDI/DayInstance.cs | 9 +- Source/EWSPDI/Duration.cs | 102 +-- Source/EWSPDI/EWSoftware.PDI.csproj | 24 +- Source/EWSPDI/FixedHoliday.cs | 10 +- Source/EWSPDI/FloatingHoliday.cs | 10 +- Source/EWSPDI/Holiday.cs | 8 +- Source/EWSPDI/HourlyFrequency.cs | 13 +- Source/EWSPDI/IFrequencyRules.cs | 7 +- Source/EWSPDI/ListItem.cs | 13 +- Source/EWSPDI/LocalizedResources.cs | 16 +- Source/EWSPDI/MinutelyFrequency.cs | 13 +- Source/EWSPDI/MonthlyFrequency.cs | 13 +- Source/EWSPDI/Period.cs | 61 +- .../EWSPDI/Properties/AssemblyInfoShared.cs | 8 +- Source/EWSPDI/{ReadMe.txt => ReadMe.md} | 3 +- Source/EWSPDI/RecurDateTime.cs | 65 +- Source/EWSPDI/RecurOptsDataSource.cs | 15 +- Source/EWSPDI/Recurrence.cs | 286 +++++--- Source/EWSPDI/RecurrenceEnumerator.cs | 13 +- Source/EWSPDI/SecondlyFrequency.cs | 13 +- Source/EWSPDI/StringCollection.cs | 15 +- Source/EWSPDI/UniqueIntegerCollection.cs | 52 +- Source/EWSPDI/WeeklyFrequency.cs | 13 +- Source/EWSPDI/YearlyFrequency.cs | 16 +- .../Binding/ChildPropertyDescriptor.cs | 8 +- .../ChildPropertyTypeDescriptionProvider.cs | 10 +- .../Binding/ChildPropertyTypeDescriptor.cs | 13 +- .../EWSPDIData/Binding/ExtendedBindingList.cs | 100 +-- Source/EWSPDIData/Binding/PropertyComparer.cs | 31 +- Source/EWSPDIData/DateTimeInstance.cs | 66 +- Source/EWSPDIData/EWSoftware.PDI.Data.csproj | 22 +- Source/EWSPDIData/EncodingUtils.cs | 37 +- Source/EWSPDIData/GlobalSuppressions.cs | Bin 93970 -> 81446 bytes Source/EWSPDIData/LocalizedResources.cs | 18 +- .../EWSPDIData/PDIObjects/CalendarObject.cs | 31 +- .../EWSPDIData/PDIObjects/ObservanceRule.cs | 113 ++- .../PDIObjects/ObservanceRuleCollection.cs | 15 +- .../EWSPDIData/PDIObjects/RecurringObject.cs | 104 ++- Source/EWSPDIData/PDIObjects/VAlarm.cs | 113 ++- .../EWSPDIData/PDIObjects/VAlarmCollection.cs | 11 +- Source/EWSPDIData/PDIObjects/VCalendar.cs | 363 +++++----- Source/EWSPDIData/PDIObjects/VCard.cs | 341 ++++----- .../EWSPDIData/PDIObjects/VCardCollection.cs | 30 +- Source/EWSPDIData/PDIObjects/VEvent.cs | 308 ++++---- .../EWSPDIData/PDIObjects/VEventCollection.cs | 17 +- Source/EWSPDIData/PDIObjects/VFreeBusy.cs | 146 ++-- .../PDIObjects/VFreeBusyCollection.cs | 19 +- Source/EWSPDIData/PDIObjects/VJournal.cs | 218 +++--- .../PDIObjects/VJournalCollection.cs | 19 +- Source/EWSPDIData/PDIObjects/VNote.cs | 85 +-- .../EWSPDIData/PDIObjects/VNoteCollections.cs | 26 +- Source/EWSPDIData/PDIObjects/VTimeZone.cs | 64 +- .../PDIObjects/VTimeZoneCollection.cs | 56 +- Source/EWSPDIData/PDIObjects/VToDo.cs | 312 ++++---- .../EWSPDIData/PDIObjects/VToDoCollection.cs | 19 +- Source/EWSPDIData/PDIParser/PDIParser.cs | 44 +- .../EWSPDIData/PDIParser/VCalendarParser.cs | 671 ++++++++++-------- Source/EWSPDIData/PDIParser/VCardParser.cs | 226 +++--- Source/EWSPDIData/PDIParser/VNoteParser.cs | 78 +- .../PDIProperties/ActionProperty.cs | 19 +- .../PDIProperties/AddressProperty.cs | 73 +- .../AddressPropertyCollection.cs | 13 +- .../EWSPDIData/PDIProperties/AgentProperty.cs | 15 +- .../PDIProperties/AgentPropertyCollection.cs | 11 +- .../PDIProperties/AnniversaryProperty.cs | 7 +- .../PDIProperties/AttachProperty.cs | 11 +- .../PDIProperties/AttendeeProperty.cs | 91 ++- .../AttendeePropertyCollection.cs | 9 +- .../PDIProperties/BaseAltRepProperty.cs | 10 +- .../PDIProperties/BaseDateTimeProperty.cs | 17 +- .../EWSPDIData/PDIProperties/BaseProperty.cs | 117 +-- .../PDIProperties/BirthDateProperty.cs | 7 +- .../EWSPDIData/PDIProperties/BodyProperty.cs | 7 +- .../PDIProperties/CalendarScaleProperty.cs | 7 +- .../PDIProperties/CategoriesProperty.cs | 37 +- .../PDIProperties/ClassificationProperty.cs | 7 +- .../PDIProperties/ClientPidMapProperty.cs | 12 +- .../PDIProperties/CommentProperty.cs | 7 +- .../PDIProperties/CompletedDateProperty.cs | 9 +- .../PDIProperties/ContactProperty.cs | 7 +- .../ContactPropertyCollection.cs | 7 +- .../PDIProperties/CustomProperty.cs | 11 +- .../PDIProperties/CustomPropertyCollection.cs | 15 +- .../PDIProperties/DateCreatedProperty.cs | 9 +- .../PDIProperties/DaylightProperty.cs | 17 +- .../PDIProperties/DescriptionProperty.cs | 7 +- .../PDIProperties/DueDateProperty.cs | 7 +- .../PDIProperties/DurationProperty.cs | 11 +- .../EWSPDIData/PDIProperties/EMailProperty.cs | 47 +- .../PDIProperties/EMailPropertyCollection.cs | 17 +- .../PDIProperties/EndDateProperty.cs | 7 +- .../PDIProperties/ExDateProperty.cs | 7 +- .../PDIProperties/ExDatePropertyCollection.cs | 9 +- .../PDIProperties/ExRuleProperty.cs | 7 +- .../PDIProperties/FormattedNameProperty.cs | 15 +- .../PDIProperties/FreeBusyProperty.cs | 18 +- .../FreeBusyPropertyCollection.cs | 9 +- .../PDIProperties/GenderProperty.cs | 21 +- .../GeographicPositionProperty.cs | 15 +- .../EWSPDIData/PDIProperties/KindProperty.cs | 18 +- .../EWSPDIData/PDIProperties/LabelProperty.cs | 38 +- .../PDIProperties/LabelPropertyCollection.cs | 21 +- .../PDIProperties/LastModifiedProperty.cs | 9 +- .../PDIProperties/LastRevisionProperty.cs | 7 +- .../PDIProperties/LocationProperty.cs | 7 +- .../EWSPDIData/PDIProperties/LogoProperty.cs | 7 +- .../PDIProperties/MailerProperty.cs | 7 +- .../PDIProperties/MemberProperty.cs | 6 +- .../PDIProperties/MethodProperty.cs | 17 +- .../PDIProperties/MimeNameProperty.cs | 7 +- .../PDIProperties/MimeSourceProperty.cs | 11 +- .../EWSPDIData/PDIProperties/NameProperty.cs | 51 +- .../PDIProperties/NicknameProperty.cs | 33 +- .../EWSPDIData/PDIProperties/NoteProperty.cs | 7 +- .../PDIProperties/NotePropertyCollection.cs | 9 +- .../PDIProperties/OrganizationProperty.cs | 43 +- .../PDIProperties/OrganizerProperty.cs | 19 +- .../PDIProperties/PercentCompleteProperty.cs | 13 +- .../EWSPDIData/PDIProperties/PhotoProperty.cs | 55 +- .../PDIProperties/PriorityProperty.cs | 11 +- .../PDIProperties/ProductIdProperty.cs | 23 +- .../PDIProperties/PublicKeyProperty.cs | 22 +- .../EWSPDIData/PDIProperties/RDateProperty.cs | 21 +- .../PDIProperties/RDatePropertyCollection.cs | 13 +- .../EWSPDIData/PDIProperties/RRuleProperty.cs | 16 +- .../PDIProperties/RecurrenceCountProperty.cs | 13 +- .../PDIProperties/RecurrenceIdProperty.cs | 13 +- .../PDIProperties/RelatedProperty.cs | 65 +- .../RelatedPropertyCollection.cs | 14 +- .../PDIProperties/RelatedToProperty.cs | 13 +- .../RelatedToPropertyCollection.cs | 6 +- .../PDIProperties/RepeatProperty.cs | 13 +- .../PDIProperties/RequestStatusProperty.cs | 23 +- .../RequestStatusPropertyCollection.cs | 9 +- .../PDIProperties/ResourcesProperty.cs | 33 +- .../EWSPDIData/PDIProperties/RoleProperty.cs | 7 +- .../PDIProperties/SequenceProperty.cs | 13 +- .../PDIProperties/SortStringProperty.cs | 7 +- .../EWSPDIData/PDIProperties/SoundProperty.cs | 27 +- .../PDIProperties/SpecificationVersions.cs | 11 +- .../PDIProperties/StartDateProperty.cs | 7 +- .../PDIProperties/StatusProperty.cs | 48 +- .../PDIProperties/SummaryProperty.cs | 7 +- .../PDIProperties/TelephoneProperty.cs | 61 +- .../TelephonePropertyCollection.cs | 21 +- .../PDIProperties/TimeStampProperty.cs | 11 +- .../PDIProperties/TimeTransparencyProperty.cs | 13 +- .../TimeZoneIdChangedEventArgs.cs | 11 +- .../PDIProperties/TimeZoneIdProperty.cs | 17 +- .../PDIProperties/TimeZoneNameProperty.cs | 14 +- .../TimeZoneNamePropertyCollection.cs | 25 +- .../PDIProperties/TimeZoneOffsetProperty.cs | 11 +- .../PDIProperties/TimeZoneProperty.cs | 15 +- .../PDIProperties/TimeZoneUrlProperty.cs | 7 +- .../EWSPDIData/PDIProperties/TitleProperty.cs | 7 +- .../PDIProperties/TriggerProperty.cs | 25 +- .../PDIProperties/UniqueIdProperty.cs | 17 +- .../EWSPDIData/PDIProperties/UrlProperty.cs | 7 +- Source/EWSPDIData/{ReadMe.txt => ReadMe.md} | 3 +- .../EWSoftware.PDI.Web.Controls.csproj | 35 +- Source/EWSPDIWeb/GlobalSuppressions.cs | Bin 5426 -> 5234 bytes Source/EWSPDIWeb/LocalizedResources.cs | 19 +- Source/EWSPDIWeb/{ReadMe.txt => ReadMe.md} | 3 +- Source/EWSPDIWeb/RecurrencePattern.bmp | Bin 246 -> 0 bytes Source/EWSPDIWeb/RecurrencePattern.cs | 46 +- Source/EWSPDIWeb/RecurrencePattern.png | Bin 0 -> 524 bytes Source/EWSPDIWeb/RecurrencePatternDesigner.cs | 28 +- Source/EWSPDIWinForms/AdvancedPattern.cs | 27 +- Source/EWSPDIWinForms/BrowseControl.bmp | Bin 246 -> 0 bytes Source/EWSPDIWinForms/BrowseControl.png | Bin 0 -> 411 bytes Source/EWSPDIWinForms/DailyPattern.cs | 20 +- .../EWSoftware.PDI.Windows.Forms.csproj | 39 +- Source/EWSPDIWinForms/GlobalSuppressions.cs | Bin 7304 -> 7332 bytes Source/EWSPDIWinForms/HolidayManager.bmp | Bin 246 -> 0 bytes Source/EWSPDIWinForms/HolidayManager.cs | 196 ++--- Source/EWSPDIWinForms/HolidayManager.png | Bin 0 -> 482 bytes .../HolidayPropertiesDlg.Designer.cs | 298 ++++---- Source/EWSPDIWinForms/HolidayPropertiesDlg.cs | 33 +- .../EWSPDIWinForms/HolidayPropertiesDlg.resx | 190 ++--- Source/EWSPDIWinForms/LocalizedResources.cs | 18 +- Source/EWSPDIWinForms/MonthlyPattern.cs | 72 +- Source/EWSPDIWinForms/PDIWinForms.Designer.cs | 245 ------- .../EWSPDIWinForms/Properties/AssemblyInfo.cs | 2 +- .../EWSPDIWinForms/{ReadMe.txt => ReadMe.md} | 3 +- Source/EWSPDIWinForms/RecurrencePattern.bmp | Bin 246 -> 0 bytes Source/EWSPDIWinForms/RecurrencePattern.cs | 79 ++- Source/EWSPDIWinForms/RecurrencePattern.png | Bin 0 -> 524 bytes .../RecurrencePropertiesDlg.Designer.cs | 45 +- .../RecurrencePropertiesDlg.resx | 82 +-- Source/EWSPDIWinForms/YearlyPattern.cs | 33 +- Source/VBNetDemos/CalendarBrowser/AboutDlg.vb | 35 +- .../CalendarBrowser/CalendarBrowser.vbproj | 2 +- .../My Project/AssemblyInfoShared.vb | 8 +- Source/VBNetDemos/CalendarBrowser/app.config | 3 - .../PDIDatesTest/PDIDatesTest.vbproj | 2 +- .../PDIParserTest/PDIParserTest.vbproj | 2 +- Source/VBNetDemos/PDIWebDemoVB/Web.config | 2 +- Source/VBNetDemos/PDIWinFormsTest/AboutDlg.vb | 5 +- .../PDIWinFormsTest/PDIWinFormsTest.vbproj | 2 +- .../RFC2445RecurTest/RFC2445RecurTest.vbproj | 2 +- Source/VBNetDemos/vCardBrowser/AboutDlg.vb | 6 +- .../VBNetDemos/vCardBrowser/AddressControl.vb | 5 +- .../vCardBrowser/VCardPropertiesDlg.vb | 5 +- Source/VBNetDemos/vCardBrowser/app.config | 3 - .../vCardBrowser/vCardBrowser.vbproj | 2 +- 261 files changed, 5034 insertions(+), 5296 deletions(-) create mode 100644 Doc/Content/VersionHistory/v2025.1.9.0.aml delete mode 100644 Source/CSharpDemos/CalendarBrowser/app.manifest delete mode 100644 Source/CSharpDemos/PDIWinFormsTest/app.manifest delete mode 100644 Source/CSharpDemos/vCardBrowser/app.manifest rename Source/EWSPDI/{ReadMe.txt => ReadMe.md} (89%) rename Source/EWSPDIData/{ReadMe.txt => ReadMe.md} (87%) rename Source/EWSPDIWeb/{ReadMe.txt => ReadMe.md} (79%) delete mode 100644 Source/EWSPDIWeb/RecurrencePattern.bmp create mode 100644 Source/EWSPDIWeb/RecurrencePattern.png delete mode 100644 Source/EWSPDIWinForms/BrowseControl.bmp create mode 100644 Source/EWSPDIWinForms/BrowseControl.png delete mode 100644 Source/EWSPDIWinForms/HolidayManager.bmp create mode 100644 Source/EWSPDIWinForms/HolidayManager.png delete mode 100644 Source/EWSPDIWinForms/PDIWinForms.Designer.cs rename Source/EWSPDIWinForms/{ReadMe.txt => ReadMe.md} (78%) delete mode 100644 Source/EWSPDIWinForms/RecurrencePattern.bmp create mode 100644 Source/EWSPDIWinForms/RecurrencePattern.png diff --git a/.editorconfig b/.editorconfig index 2930da2..33e3093 100644 --- a/.editorconfig +++ b/.editorconfig @@ -51,30 +51,30 @@ dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case # Symbol specifications dotnet_naming_symbols.interface.applicable_kinds = interface dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interface.required_modifiers = +dotnet_naming_symbols.interface.required_modifiers = dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types.required_modifiers = +dotnet_naming_symbols.types.required_modifiers = dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.non_field_members.required_modifiers = +dotnet_naming_symbols.non_field_members.required_modifiers = # Naming styles dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case # Code style settings @@ -92,9 +92,9 @@ dotnet_style_prefer_conditional_expression_over_assignment = true:silent dotnet_style_prefer_conditional_expression_over_return = true:silent dotnet_style_prefer_inferred_tuple_names = true:suggestion dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion -dotnet_style_prefer_compound_assignment = true:none +dotnet_style_prefer_compound_assignment = true:suggestion dotnet_style_prefer_simplified_interpolation = true:suggestion -dotnet_style_namespace_match_folder = true:suggestion +dotnet_style_namespace_match_folder = true:none dotnet_style_operator_placement_when_wrapping = beginning_of_line # "This." and "Me." qualification. Use is preferred where true but the lightbulbs tend to show up in places @@ -111,46 +111,22 @@ dotnet_diagnostic.CA1303.severity = none # IDE0010: Add missing cases dotnet_diagnostic.IDE0010.severity = none -# IDE0032: Use auto property -dotnet_diagnostic.IDE0032.severity = none - -# IDE0045: Convert to conditional expression -dotnet_diagnostic.IDE0045.severity = none - -# IDE0046: Convert to conditional expression -dotnet_diagnostic.IDE0046.severity = none - -# IDE0047: Remove unnecessary parentheses -dotnet_diagnostic.IDE0047.severity = none - -# IDE0055: Fix formatting -dotnet_diagnostic.IDE0055.severity = none - -# IDE0058: Expression value is never used -dotnet_diagnostic.IDE0058.severity = none - # IDE1006: Naming Styles dotnet_diagnostic.IDE1006.severity = none # These are disabled as we're still targeting .NET Framework as well and I don't want a lot of conditional code -# to suppress these. +# to suppress these or I'm not ready to use them just yet. # IDE0056: Use index operator dotnet_diagnostic.IDE0056.severity = none # IDE0057: Use range operator dotnet_diagnostic.IDE0057.severity = none -# IDE0063: Use simple 'using' statement -dotnet_diagnostic.IDE0063.severity = none - # IDE0066: Convert switch statement to expression dotnet_diagnostic.IDE0066.severity = none -# IDE0074: Use compound assignment -dotnet_diagnostic.IDE0074.severity = none - -# IDE0090: Use 'new(...)' -dotnet_diagnostic.IDE0090.severity = none +# CA1510: Use ArgumentNullException throw helper +dotnet_diagnostic.CA1510.severity = none # CA1845: Use span-based 'string.Concat' dotnet_diagnostic.CA1845.severity = none @@ -158,11 +134,27 @@ dotnet_diagnostic.CA1845.severity = none # CA1846: Prefer 'AsSpan' over 'Substring' dotnet_diagnostic.CA1846.severity = none +# CA1863: Use 'CompositeFormat' +dotnet_diagnostic.CA1863.severity = none + +# CA1865: Use char overload +dotnet_diagnostic.CA1865.severity = none + +# CA2249: Consider using 'string.Contains' instead of 'string.IndexOf' +dotnet_diagnostic.CA2249.severity = none + +# SYSLIB1045: Convert to 'GeneratedRegexAttribute'. +dotnet_diagnostic.SYSLIB1045.severity = none + +# SYSLIB1054: Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time +dotnet_diagnostic.SYSLIB1054.severity = none + [*.cs] # CSharp code style settings csharp_style_var_elsewhere = false:none csharp_style_var_for_built_in_types = false:none csharp_style_var_when_type_is_apparent = false:none +csharp_style_prefer_primary_constructors = false:none csharp_style_expression_bodied_accessors = true:suggestion csharp_style_expression_bodied_constructors = false:none @@ -187,7 +179,7 @@ csharp_style_prefer_null_check_over_type_check = true:suggestion csharp_style_prefer_local_over_anonymous_function = true:suggestion csharp_style_prefer_index_operator = true:suggestion csharp_style_prefer_range_operator = true:suggestion -csharp_style_implicit_object_creation_when_type_is_apparent = true:none +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion csharp_style_prefer_tuple_swap = true:suggestion csharp_style_prefer_utf8_string_literals = true:suggestion csharp_style_unused_value_assignment_preference = discard_variable:suggestion @@ -195,7 +187,7 @@ csharp_style_unused_value_expression_statement_preference = discard_variable:sil csharp_prefer_braces = when_multiline:none csharp_prefer_simple_default_expression = true:suggestion -csharp_prefer_simple_using_statement = true:none +csharp_prefer_simple_using_statement = true:suggestion csharp_preserve_single_line_blocks = true csharp_using_directive_placement = outside_namespace:silent diff --git a/Doc/Content/VersionHistory/VersionHistory.aml b/Doc/Content/VersionHistory/VersionHistory.aml index e68af72..551e68e 100644 --- a/Doc/Content/VersionHistory/VersionHistory.aml +++ b/Doc/Content/VersionHistory/VersionHistory.aml @@ -15,6 +15,11 @@ Data Interchange (PDI) Library over the life of the project.Select a version below to see a description of its changes. + + + + + diff --git a/Doc/Content/VersionHistory/v2025.1.9.0.aml b/Doc/Content/VersionHistory/v2025.1.9.0.aml new file mode 100644 index 0000000..82b9d3c --- /dev/null +++ b/Doc/Content/VersionHistory/v2025.1.9.0.aml @@ -0,0 +1,33 @@ + + + + + Release notes for version 2025.1.9.0. + + +
+ + + + Removed support for .NET 6 and added support for .NET 8 and later. + + + + Enabled nullable reference types in all projects and updated the classes to support them. + + + + Fixed an inconsistency with how the version property was applied when parsing vCard files. + + + + + +
+ + + + + +
+
diff --git a/Doc/ContentLayout.content b/Doc/ContentLayout.content index 5547ece..b107d06 100644 --- a/Doc/ContentLayout.content +++ b/Doc/ContentLayout.content @@ -117,7 +117,12 @@ - + + + + + + diff --git a/Doc/EWSoftwarePDI.shfbproj b/Doc/EWSoftwarePDI.shfbproj index 6205908..d208a1e 100644 --- a/Doc/EWSoftwarePDI.shfbproj +++ b/Doc/EWSoftwarePDI.shfbproj @@ -29,7 +29,7 @@ .NET Framework 4.0 EWSoftware.PDI Namespace Documentation https://github.com/EWSoftware/PDI - [v{%40HelpFileVersion}] Copyright \xA9 2003-2023, Eric Woodruff, All Rights Reserved + [v{%40HelpFileVersion}] Copyright \xA9 2003-2025, Eric Woodruff, All Rights Reserved Eric%40EWoodruff.us Default2022 Standard @@ -49,7 +49,7 @@ Personal Data Interchange ASP.NET web server control designers developed by Eric Woodruff. Personal Data Interchange Windows Forms controls developed by Eric Woodruff. - 2022.1.2.0 + 2025.1.9.0 @@ -195,6 +195,7 @@ + diff --git a/IgnoredWords.dic b/IgnoredWords.dic index cf026bd..c046ae9 100644 --- a/IgnoredWords.dic +++ b/IgnoredWords.dic @@ -1,10 +1,20 @@ +busys Dest ics iso +loc Mins navbar nd +pdi +pid +relateds rdt +todos +tos +tz +tzid +utc utils vcalendar vcard diff --git a/MasterBuild.bat b/MasterBuild.bat index da2cb49..2e6f38e 100644 --- a/MasterBuild.bat +++ b/MasterBuild.bat @@ -10,12 +10,6 @@ DEL Source\EWSPDIData\bin\Release\*.nupkg DEL Source\EWSPDIWeb\bin\Release\*.nupkg DEL Source\EWSPDIWinForms\bin\Release\*.nupkg -IF EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\MSBuild\15.0" SET "MSBUILD=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\MSBuild\15.0\bin\MSBuild.exe" -IF EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Professional\MSBuild\15.0" SET "MSBUILD=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\bin\MSBuild.exe" -IF EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0" SET "MSBUILD=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\bin\MSBuild.exe" -IF EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\MSBuild\Current" SET "MSBUILD=%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\MSBuild\Current\bin\MSBuild.exe" -IF EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Professional\MSBuild\Current" SET "MSBUILD=%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Professional\MSBuild\Current\bin\MSBuild.exe" -IF EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current" SET "MSBUILD=%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\bin\MSBuild.exe" IF EXIST "%ProgramFiles%\Microsoft Visual Studio\2022\Community\MSBuild\Current" SET "MSBUILD=%ProgramFiles%\Microsoft Visual Studio\2022\Community\MSBuild\Current\bin\MSBuild.exe" IF EXIST "%ProgramFiles%\Microsoft Visual Studio\2022\Professional\MSBuild\Current" SET "MSBUILD=%ProgramFiles%\Microsoft Visual Studio\2022\Professional\MSBuild\Current\bin\MSBuild.exe" IF EXIST "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current" SET "MSBUILD=%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\bin\MSBuild.exe" diff --git a/Source/CSharpDemos/CalendarBrowser/AboutDlg.cs b/Source/CSharpDemos/CalendarBrowser/AboutDlg.cs index dcb4732..8fec7d7 100644 --- a/Source/CSharpDemos/CalendarBrowser/AboutDlg.cs +++ b/Source/CSharpDemos/CalendarBrowser/AboutDlg.cs @@ -1,9 +1,8 @@ //=============================================================================================================== // File : AboutDlg.cs // Author : Eric Woodruff -// Updated : 11/23/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This form is used to display application version information // @@ -50,13 +49,13 @@ public AboutDlg() private void AboutDlg_Load(object sender, EventArgs e) { // Get assembly information not available from the application object - Assembly asm = Assembly.GetEntryAssembly(); + Assembly asm = Assembly.GetEntryAssembly()!; AssemblyTitleAttribute title = (AssemblyTitleAttribute) - AssemblyTitleAttribute.GetCustomAttribute(asm, typeof(AssemblyTitleAttribute)); + Attribute.GetCustomAttribute(asm, typeof(AssemblyTitleAttribute))!; AssemblyCopyrightAttribute copyright = (AssemblyCopyrightAttribute) - AssemblyCopyrightAttribute.GetCustomAttribute(asm, typeof(AssemblyCopyrightAttribute)); + Attribute.GetCustomAttribute(asm, typeof(AssemblyCopyrightAttribute))!; AssemblyDescriptionAttribute desc = (AssemblyDescriptionAttribute) - AssemblyDescriptionAttribute.GetCustomAttribute(asm, typeof(AssemblyDescriptionAttribute)); + Attribute.GetCustomAttribute(asm, typeof(AssemblyDescriptionAttribute))!; // Set the labels lblName.Text = title.Title; @@ -68,7 +67,7 @@ private void AboutDlg_Load(object sender, EventArgs e) foreach(AssemblyName an in asm.GetReferencedAssemblies()) { ListViewItem lvi = lvComponents.Items.Add(an.Name); - lvi.SubItems.Add(an.Version.ToString()); + lvi.SubItems.Add(an.Version!.ToString()); } lvComponents.Sorting = SortOrder.Ascending; @@ -109,7 +108,11 @@ private void lnkHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) try { // Launch the e-mail URL, this will fail if user does not have an association for e-mail URLs - System.Diagnostics.Process.Start((string)e.Link.LinkData); + System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo + { + FileName = (string)e.Link!.LinkData!, + UseShellExecute = true, + }); } catch(Exception ex) { diff --git a/Source/CSharpDemos/CalendarBrowser/AlarmControl.cs b/Source/CSharpDemos/CalendarBrowser/AlarmControl.cs index 28da11f..a178052 100644 --- a/Source/CSharpDemos/CalendarBrowser/AlarmControl.cs +++ b/Source/CSharpDemos/CalendarBrowser/AlarmControl.cs @@ -2,9 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : AlarmControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Visual C# +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a calendar object's alarm collection properties // @@ -38,7 +37,7 @@ public partial class AlarmControl : EWSoftware.PDI.Windows.Forms.BrowseControl #region Private data members //===================================================================== - private VAlarm currentAlarm; + private VAlarm? currentAlarm; #endregion @@ -93,7 +92,7 @@ public override void BindToControls() txtDescription.DataBindings.Add("Text", this.BindingSource, "Description_Value"); // The binding events translate between the index value and the action type - Binding b = new Binding("SelectedIndex", this.BindingSource, "Action_Action"); + Binding b = new("SelectedIndex", this.BindingSource, "Action_Action"); b.Format += AlarmAction_Format; b.Parse += AlarmAction_Parse; cboAction.DataBindings.Add(b); @@ -137,12 +136,14 @@ public bool ValidateItems() } if(a.Action.Action == AlarmAction.EMail) + { if(String.IsNullOrWhiteSpace(a.Summary.Value)) { this.ErrorProvider.SetError(txtSummary, "A summary is required for an e-mail alarm"); result = false; } else + { if(result && a.Attendees.Count == 0) { tabInfo.SelectedTab = pgAttendees; @@ -150,6 +151,8 @@ public bool ValidateItems() "an e-mail alarm"); result = false; } + } + } if(!result) break; @@ -193,7 +196,7 @@ private void StoreChanges() /// /// The old time zone's ID /// The new time zone's ID - public void ApplyTimeZone(string oldTZ, string newTZ) + public void ApplyTimeZone(string? oldTZ, string? newTZ) { DateTimeInstance dti; @@ -218,9 +221,9 @@ public void ApplyTimeZone(string oldTZ, string newTZ) /// /// The sender of the event /// The event arguments - private void AlarmAction_Format(object sender, ConvertEventArgs e) + private void AlarmAction_Format(object? sender, ConvertEventArgs e) { - e.Value = (int)e.Value; + e.Value = (int)e.Value!; } /// @@ -228,9 +231,9 @@ private void AlarmAction_Format(object sender, ConvertEventArgs e) /// /// The sender of the event /// The event arguments - private void AlarmAction_Parse(object sender, ConvertEventArgs e) + private void AlarmAction_Parse(object? sender, ConvertEventArgs e) { - e.Value = (AlarmAction)e.Value; + e.Value = (AlarmAction)e.Value!; } /// @@ -239,9 +242,9 @@ private void AlarmAction_Parse(object sender, ConvertEventArgs e) /// /// The sender of the event /// The event arguments - private void BindingSource_PositionChanged(object sender, EventArgs e) + private void BindingSource_PositionChanged(object? sender, EventArgs e) { - VAlarm newItem = (VAlarm)this.BindingSource.Current; + VAlarm? newItem = (VAlarm)this.BindingSource.Current; // If all deleted, ignore it if(newItem == null) @@ -352,7 +355,7 @@ private void Duration_Validating(object sender, CancelEventArgs e) t.Text = t.Text.Trim(); - if(t.Text.Length != 0 && !Duration.TryParse(t.Text, out Duration d)) + if(t.Text.Length != 0 && !Duration.TryParse(t.Text, out _)) { this.ErrorProvider.SetError(t, "Invalid duration value"); e.Cancel = true; diff --git a/Source/CSharpDemos/CalendarBrowser/AttachmentsControl.cs b/Source/CSharpDemos/CalendarBrowser/AttachmentsControl.cs index c1b36de..1a1f9da 100644 --- a/Source/CSharpDemos/CalendarBrowser/AttachmentsControl.cs +++ b/Source/CSharpDemos/CalendarBrowser/AttachmentsControl.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : AttachmentsControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a calendar object's attachment properties // @@ -29,12 +29,12 @@ namespace CalendarBrowser /// /// This is used to edit a calendar object's attachment properties /// - public partial class AttachmentsControl : System.Windows.Forms.UserControl + public partial class AttachmentsControl : UserControl { #region Private data members //===================================================================== - private AttachPropertyCollection attach; + private readonly AttachPropertyCollection attach; #endregion @@ -48,7 +48,7 @@ public AttachmentsControl() { InitializeComponent(); - attach = new AttachPropertyCollection(); + attach = []; this.SetButtonStates(); } #endregion @@ -128,14 +128,13 @@ private void lbAttachments_SelectedIndexChanged(object sender, EventArgs e) /// The event arguments private void btnLoad_Click(object sender, EventArgs e) { - using(OpenFileDialog dlg = new OpenFileDialog()) - { - dlg.Title = "Add Attachment"; - dlg.InitialDirectory = Environment.CurrentDirectory; + using var dlg = new OpenFileDialog(); + + dlg.Title = "Add Attachment"; + dlg.InitialDirectory = Environment.CurrentDirectory; - if(dlg.ShowDialog() == DialogResult.OK) - txtFilename.Text = dlg.FileName; - } + if(dlg.ShowDialog() == DialogResult.OK) + txtFilename.Text = dlg.FileName; } /// @@ -166,7 +165,7 @@ private void btnAdd_Click(object sender, EventArgs e) { this.Cursor = Cursors.WaitCursor; - AttachProperty a = new AttachProperty + var a = new AttachProperty { FormatType = (txtFormat.Text.Trim().Length == 0) ? null : txtFormat.Text }; @@ -180,14 +179,13 @@ private void btnAdd_Click(object sender, EventArgs e) } else { - using(var fs = new FileStream(txtFilename.Text, FileMode.Open, FileAccess.Read)) - { - byte[] byData = new byte[fs.Length]; - fs.Read(byData, 0, byData.Length); + using var fs = new FileStream(txtFilename.Text, FileMode.Open, FileAccess.Read); - a.ValueLocation = ValLocValue.Binary; - a.SetAttachmentBytes(byData); - } + byte[] byData = new byte[fs.Length]; + _ = fs.Read(byData, 0, byData.Length); + + a.ValueLocation = ValLocValue.Binary; + a.SetAttachmentBytes(byData); desc = $"Inline - {a.FormatType}"; } @@ -257,44 +255,42 @@ private void btnClear_Click(object sender, EventArgs e) /// The event arguments private void btnDetach_Click(object sender, EventArgs e) { - using(SaveFileDialog dlg = new SaveFileDialog()) + using var dlg = new SaveFileDialog(); + + dlg.Title = "Save Inline Attachment"; + dlg.InitialDirectory = Environment.CurrentDirectory; + + if(dlg.ShowDialog() == DialogResult.OK) { - dlg.Title = "Save Inline Attachment"; - dlg.InitialDirectory = Environment.CurrentDirectory; + try + { + this.Cursor = Cursors.WaitCursor; - if(dlg.ShowDialog() == DialogResult.OK) + // Open the file and write the data to it + using var fs = new FileStream(dlg.FileName, FileMode.Create, FileAccess.Write); + + byte[] byData = attach[lbAttachments.SelectedIndex].GetAttachmentBytes(); + fs.Write(byData, 0, byData.Length); + } + catch(Exception ex) { - try - { - this.Cursor = Cursors.WaitCursor; - - // Open the file and write the data to it - using(var fs = new FileStream(dlg.FileName, FileMode.Create, FileAccess.Write)) - { - byte[] byData = attach[lbAttachments.SelectedIndex].GetAttachmentBytes(); - fs.Write(byData, 0, byData.Length); - } - } - catch(Exception ex) - { - string error = $"Unable to save attachment:\n{ex.Message}"; + string error = $"Unable to save attachment:\n{ex.Message}"; - if(ex.InnerException != null) - { - error += ex.InnerException.Message + "\n"; + if(ex.InnerException != null) + { + error += ex.InnerException.Message + "\n"; - if(ex.InnerException.InnerException != null) - error += ex.InnerException.InnerException.Message; - } + if(ex.InnerException.InnerException != null) + error += ex.InnerException.InnerException.Message; + } - System.Diagnostics.Debug.Write(ex); + System.Diagnostics.Debug.Write(ex); - MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - finally - { - this.Cursor = Cursors.Default; - } + MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + this.Cursor = Cursors.Default; } } } diff --git a/Source/CSharpDemos/CalendarBrowser/AttendeeControl.cs b/Source/CSharpDemos/CalendarBrowser/AttendeeControl.cs index 09406a1..8eb9d6f 100644 --- a/Source/CSharpDemos/CalendarBrowser/AttendeeControl.cs +++ b/Source/CSharpDemos/CalendarBrowser/AttendeeControl.cs @@ -2,9 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : AttendeeControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Visual C# +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a calendar object's attendee collection // @@ -77,12 +76,12 @@ public override void BindToControls() chkRSVP.DataBindings.Add("Checked", this.BindingSource, "Rsvp"); // For the combo boxes, we'll handle unknown values too via the binding events - Binding b = new Binding("SelectedIndex", this.BindingSource, "Role"); + Binding b = new("SelectedIndex", this.BindingSource, "Role"); b.Format += RoleStatus_Format; b.Parse += RoleStatus_Parse; cboRole.DataBindings.Add(b); - b = new Binding("SelectedIndex", this.BindingSource, "ParticipationStatus"); + b = new("SelectedIndex", this.BindingSource, "ParticipationStatus"); b.Format += RoleStatus_Format; b.Parse += RoleStatus_Parse; cboStatus.DataBindings.Add(b); @@ -97,9 +96,9 @@ public override void BindToControls() /// /// The sender of the event /// The event arguments - private void RoleStatus_Format(object sender, ConvertEventArgs e) + private void RoleStatus_Format(object? sender, ConvertEventArgs e) { - ComboBox c = (ComboBox)(((Binding)sender).Control); + ComboBox c = (ComboBox)(((Binding)sender!).Control); int idx; if(e.Value == null) @@ -120,9 +119,9 @@ private void RoleStatus_Format(object sender, ConvertEventArgs e) /// /// The sender of the event /// The event arguments - private void RoleStatus_Parse(object sender, ConvertEventArgs e) + private void RoleStatus_Parse(object? sender, ConvertEventArgs e) { - ComboBox c = (ComboBox)(((Binding)sender).Control); + ComboBox c = (ComboBox)(((Binding)sender!).Control); if(c.SelectedIndex != -1) e.Value = c.Items[c.SelectedIndex]; diff --git a/Source/CSharpDemos/CalendarBrowser/CalendarBrowser.csproj b/Source/CSharpDemos/CalendarBrowser/CalendarBrowser.csproj index 84e64ea..11cdffc 100644 --- a/Source/CSharpDemos/CalendarBrowser/CalendarBrowser.csproj +++ b/Source/CSharpDemos/CalendarBrowser/CalendarBrowser.csproj @@ -1,26 +1,28 @@  - - WinExe - net6.0-windows;net40 - true - False - False - False - False - False - False - ProductAttribute - CalendarBrowser.snk - true - true - AllEnabledByDefault - - - - - - - - - + + WinExe + net8.0-windows;net40 + true + False + False + False + False + False + False + ProductAttribute + CalendarBrowser.snk + true + true + AllEnabledByDefault + latest + enable + + + + + + + + + \ No newline at end of file diff --git a/Source/CSharpDemos/CalendarBrowser/CalendarBrowserForm.cs b/Source/CSharpDemos/CalendarBrowser/CalendarBrowserForm.cs index 6982f6c..4705ef8 100644 --- a/Source/CSharpDemos/CalendarBrowser/CalendarBrowserForm.cs +++ b/Source/CSharpDemos/CalendarBrowser/CalendarBrowserForm.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : CalendarBrowserForm.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is a simple demonstration application that shows how to load, save, and manage vCalendar and iCalendar // files including how to edit the properties on the various components. @@ -37,7 +37,7 @@ namespace CalendarBrowser /// This application demonstrates loading, saving, and managing a vCalendar or iCalendar file including how /// to edit the properties on the various components. /// - public partial class CalendarBrowserForm : System.Windows.Forms.Form + public partial class CalendarBrowserForm : Form { #region Private data members //===================================================================== @@ -182,7 +182,7 @@ private void LoadGridWithItems(bool connectEvents) /// /// The sender of the event /// The event arguments - private void Calendar_ListChanged(object sender, ListChangedEventArgs e) + private void Calendar_ListChanged(object? sender, ListChangedEventArgs e) { int count; @@ -234,82 +234,82 @@ private void miOpen_Click(object sender, EventArgs e) MessageBoxDefaultButton.Button2) == DialogResult.No) return; - using(OpenFileDialog dlg = new OpenFileDialog()) - { - dlg.Title = "Load Calendar File"; - dlg.Filter = "ICS files (*.ics)|*.ics|VCS files (*.vcs)|*.vcs|All files (*.*)|*.*"; + using var dlg = new OpenFileDialog(); + + dlg.Title = "Load Calendar File"; + dlg.Filter = "ICS files (*.ics)|*.ics|VCS files (*.vcs)|*.vcs|All files (*.*)|*.*"; - if(vCal.Version == SpecificationVersions.vCalendar10) - { - dlg.DefaultExt = "vcs"; - dlg.FilterIndex = 2; - } - else - { - dlg.DefaultExt = "ics"; - dlg.FilterIndex = 1; - } + if(vCal.Version == SpecificationVersions.vCalendar10) + { + dlg.DefaultExt = "vcs"; + dlg.FilterIndex = 2; + } + else + { + dlg.DefaultExt = "ics"; + dlg.FilterIndex = 1; + } - dlg.InitialDirectory = Path.GetFullPath(Path.Combine( - Environment.CurrentDirectory, @"..\..\..\..\..\PDIFiles")); + dlg.InitialDirectory = Path.GetFullPath(Path.Combine( + Environment.CurrentDirectory, @"..\..\..\..\..\PDIFiles")); - if(dlg.ShowDialog() == DialogResult.OK) + if(dlg.ShowDialog() == DialogResult.OK) + { + try { - try - { - this.Cursor = Cursors.WaitCursor; + this.Cursor = Cursors.WaitCursor; - // Parse the calendar information from the file and load the data grid with some basic - // information about the items in it. - vCal.Dispose(); - vCal = VCalendarParser.ParseFromFile(dlg.FileName); + // Parse the calendar information from the file and load the data grid with some basic + // information about the items in it. + vCal.Dispose(); + vCal = VCalendarParser.ParseFromFile(dlg.FileName) ?? + throw new InvalidOperationException("Invalid calendar file"); - LoadComponentList(); + LoadComponentList(); - // Find the first collection with items - if(vCal.Events.Count != 0) - cboComponents.SelectedIndex = 0; + // Find the first collection with items + if(vCal.Events.Count != 0) + cboComponents.SelectedIndex = 0; + else + { + if(vCal.ToDos.Count != 0) + cboComponents.SelectedIndex = 1; else { - if(vCal.ToDos.Count != 0) - cboComponents.SelectedIndex = 1; + if(vCal.Journals.Count != 0) + cboComponents.SelectedIndex = 2; else { - if(vCal.Journals.Count != 0) - cboComponents.SelectedIndex = 2; + if(vCal.FreeBusys.Count != 0) + cboComponents.SelectedIndex = 3; else - { - if(vCal.FreeBusys.Count != 0) - cboComponents.SelectedIndex = 3; - else - cboComponents.SelectedIndex = 0; - } + cboComponents.SelectedIndex = 0; } } - - LoadGridWithItems(true); - lblFilename.Text = dlg.FileName; } - catch(Exception ex) - { - string error = $"Unable to load calendar:\n{ex.Message}"; - - if(ex.InnerException != null) - { - error += ex.InnerException.Message + "\n"; - - if(ex.InnerException.InnerException != null) - error += ex.InnerException.InnerException.Message; - } - System.Diagnostics.Debug.Write(ex); + LoadGridWithItems(true); + lblFilename.Text = dlg.FileName; + } + catch(Exception ex) + { + string error = $"Unable to load calendar:\n{ex.Message}"; - MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - finally + if(ex.InnerException != null) { - this.Cursor = Cursors.Default; + error += ex.InnerException.Message + "\n"; + + if(ex.InnerException.InnerException != null) + error += ex.InnerException.InnerException.Message; } + + System.Diagnostics.Debug.Write(ex); + + MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + this.Cursor = Cursors.Default; } } } @@ -321,62 +321,61 @@ private void miOpen_Click(object sender, EventArgs e) /// The event arguments private void miSave_Click(object sender, EventArgs e) { - using(SaveFileDialog dlg = new SaveFileDialog()) - { - dlg.Title = "Save Calendar File"; - dlg.Filter = "ICS files (*.ics)|*.ics|VCS files (*.vcs)|*.vcs|All files (*.*)|*.*"; + using var dlg = new SaveFileDialog(); + + dlg.Title = "Save Calendar File"; + dlg.Filter = "ICS files (*.ics)|*.ics|VCS files (*.vcs)|*.vcs|All files (*.*)|*.*"; - if(vCal.Version == SpecificationVersions.vCalendar10) - { - dlg.DefaultExt = "vcs"; - dlg.FilterIndex = 2; - } - else - { - dlg.DefaultExt = "ics"; - dlg.FilterIndex = 1; - } + if(vCal.Version == SpecificationVersions.vCalendar10) + { + dlg.DefaultExt = "vcs"; + dlg.FilterIndex = 2; + } + else + { + dlg.DefaultExt = "ics"; + dlg.FilterIndex = 1; + } - dlg.InitialDirectory = Path.GetFullPath(Path.Combine( - Environment.CurrentDirectory, @"..\..\..\..\..\PDIFiles")); - dlg.FileName = lblFilename.Text; + dlg.InitialDirectory = Path.GetFullPath(Path.Combine( + Environment.CurrentDirectory, @"..\..\..\..\..\PDIFiles")); + dlg.FileName = lblFilename.Text; - if(dlg.ShowDialog() == DialogResult.OK) + if(dlg.ShowDialog() == DialogResult.OK) + { + try { - try + this.Cursor = Cursors.WaitCursor; + + // Open the file and write the calendar to it. We'll use the same encoding method used by + // the parser. + using(var sw = new StreamWriter(dlg.FileName, false, PDIParser.DefaultEncoding)) { - this.Cursor = Cursors.WaitCursor; + vCal.WriteToStream(sw); + } - // Open the file and write the calendar to it. We'll use the same encoding method used by - // the parser. - using(var sw = new StreamWriter(dlg.FileName, false, PDIParser.DefaultEncoding)) - { - vCal.WriteToStream(sw); - } + wasModified = false; + lblFilename.Text = dlg.FileName; + } + catch(Exception ex) + { + string error = $"Unable to save calendar:\n{ex.Message}"; - wasModified = false; - lblFilename.Text = dlg.FileName; - } - catch(Exception ex) + if(ex.InnerException != null) { - string error = $"Unable to save calendar:\n{ex.Message}"; - - if(ex.InnerException != null) - { - error += ex.InnerException.Message + "\n"; + error += ex.InnerException.Message + "\n"; - if(ex.InnerException.InnerException != null) - error += ex.InnerException.InnerException.Message; - } + if(ex.InnerException.InnerException != null) + error += ex.InnerException.InnerException.Message; + } - System.Diagnostics.Debug.Write(ex); + System.Diagnostics.Debug.Write(ex); - MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - finally - { - this.Cursor = Cursors.Default; - } + MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + this.Cursor = Cursors.Default; } } } @@ -405,10 +404,9 @@ private void miClear_Click(object sender, EventArgs e) /// The event arguments private void miAbout_Click(object sender, EventArgs e) { - using(AboutDlg dlg = new AboutDlg()) - { - dlg.ShowDialog(); - } + using var dlg = new AboutDlg(); + + dlg.ShowDialog(); } /// @@ -431,9 +429,9 @@ private void btnAdd_Click(object sender, EventArgs e) switch(cboComponents.SelectedIndex) { case 0: - using(CalendarObjectDlg dlg = new CalendarObjectDlg()) + using(var dlg = new CalendarObjectDlg()) { - VEvent evt = new VEvent(); + var evt = new VEvent(); evt.UniqueId.AssignNewId(true); evt.DateCreated.TimeZoneDateTime = DateTime.Now; evt.LastModified.TimeZoneDateTime = evt.DateCreated.TimeZoneDateTime; @@ -452,9 +450,9 @@ private void btnAdd_Click(object sender, EventArgs e) break; case 1: - using(CalendarObjectDlg dlg = new CalendarObjectDlg()) + using(var dlg = new CalendarObjectDlg()) { - VToDo td = new VToDo(); + var td = new VToDo(); td.DateCreated.TimeZoneDateTime = DateTime.Now; td.LastModified.TimeZoneDateTime = td.DateCreated.TimeZoneDateTime; dlg.SetValues(td); @@ -472,9 +470,9 @@ private void btnAdd_Click(object sender, EventArgs e) break; case 2: - using(CalendarObjectDlg dlg = new CalendarObjectDlg()) + using(var dlg = new CalendarObjectDlg()) { - VJournal j = new VJournal(); + var j = new VJournal(); j.DateCreated.TimeZoneDateTime = DateTime.Now; j.LastModified.TimeZoneDateTime = j.DateCreated.TimeZoneDateTime; dlg.SetValues(j); @@ -492,11 +490,11 @@ private void btnAdd_Click(object sender, EventArgs e) break; case 3: - using(VFreeBusyDlg dlg = new VFreeBusyDlg()) + using(var dlg = new VFreeBusyDlg()) { if(dlg.ShowDialog() == DialogResult.OK) { - VFreeBusy fb = new VFreeBusy(); + var fb = new VFreeBusy(); dlg.GetValues(fb); // Create a unique ID for the new item @@ -526,7 +524,7 @@ private void btnEdit_Click(object sender, EventArgs e) switch(cboComponents.SelectedIndex) { case 0: - using(CalendarObjectDlg dlg = new CalendarObjectDlg()) + using(var dlg = new CalendarObjectDlg()) { dlg.SetValues(vCal.Events[dgvCalendar.CurrentCellAddress.Y]); @@ -540,7 +538,7 @@ private void btnEdit_Click(object sender, EventArgs e) break; case 1: - using(CalendarObjectDlg dlg = new CalendarObjectDlg()) + using(var dlg = new CalendarObjectDlg()) { dlg.SetValues(vCal.ToDos[dgvCalendar.CurrentCellAddress.Y]); @@ -554,7 +552,7 @@ private void btnEdit_Click(object sender, EventArgs e) break; case 2: - using(CalendarObjectDlg dlg = new CalendarObjectDlg()) + using(var dlg = new CalendarObjectDlg()) { dlg.SetValues(vCal.Journals[dgvCalendar.CurrentCellAddress.Y]); @@ -568,7 +566,7 @@ private void btnEdit_Click(object sender, EventArgs e) break; case 3: - using(VFreeBusyDlg dlg = new VFreeBusyDlg()) + using(var dlg = new VFreeBusyDlg()) { dlg.SetValues(vCal.FreeBusys[dgvCalendar.CurrentCellAddress.Y]); @@ -691,17 +689,16 @@ private void cboComponents_SelectedIndexChanged(object sender, EventArgs e) /// The event arguments private void btnChgTimeZone_Click(object sender, EventArgs e) { - using(TimeZoneListDlg dlg = new TimeZoneListDlg()) - { - dlg.CurrentCalendar = vCal; - dlg.Modified = wasModified; - dlg.ShowDialog(); + using var dlg = new TimeZoneListDlg(); + + dlg.CurrentCalendar = vCal; + dlg.Modified = wasModified; + dlg.ShowDialog(); - if(wasModified != dlg.Modified) - { - wasModified = true; - LoadGridWithItems(false); - } + if(wasModified != dlg.Modified) + { + wasModified = true; + LoadGridWithItems(false); } } @@ -789,7 +786,7 @@ private void ChangePropEncoding_Click(object sender, EventArgs e) private static int CalendarSorter(CalendarObject x, CalendarObject y) { DateTime d1, d2; - string summary1, summary2; + string? summary1, summary2; if(x is VEvent e1) { @@ -836,11 +833,8 @@ private static int CalendarSorter(CalendarObject x, CalendarObject y) if(d1.CompareTo(d2) == 0) { - if(summary1 == null) - summary1 = String.Empty; - - if(summary2 == null) - summary2 = String.Empty; + summary1 ??= String.Empty; + summary2 ??= String.Empty; // For descending order, change this to compare summary 2 to summary 1 instead return String.Compare(summary1, summary2, StringComparison.Ordinal); @@ -860,18 +854,18 @@ private void dgvCalendar_CellPainting(object sender, DataGridViewCellPaintingEve { CurrencyManager cm; StartDateProperty startProp; - SummaryProperty summaryProp; - DescriptionProperty descProp; + SummaryProperty? summaryProp; + DescriptionProperty? descProp; DateTimeInstance dti; Color foreColor; object item; - string columnText = null; + string? columnText = null; if(e.RowIndex > -1 && (e.ColumnIndex == 0 || e.ColumnIndex == 1)) { - cm = (CurrencyManager)dgvCalendar.BindingContext[dgvCalendar.DataSource]; - item = cm.List[e.RowIndex]; + cm = (CurrencyManager)dgvCalendar.BindingContext![dgvCalendar.DataSource]; + item = cm.List[e.RowIndex]!; if(e.ColumnIndex == 0) { @@ -950,14 +944,13 @@ private void dgvCalendar_CellPainting(object sender, DataGridViewCellPaintingEve // Based the foreground color on the selected state if((e.State & DataGridViewElementStates.Selected) != 0) - foreColor = e.CellStyle.SelectionForeColor; + foreColor = e.CellStyle!.SelectionForeColor; else - foreColor = e.CellStyle.ForeColor; + foreColor = e.CellStyle!.ForeColor; - using(SolidBrush b = new SolidBrush(foreColor)) - { - e.Graphics.DrawString(columnText, e.CellStyle.Font, b, e.CellBounds, sf); - } + using var b = new SolidBrush(foreColor); + + e.Graphics!.DrawString(columnText, e.CellStyle.Font, b, e.CellBounds, sf); e.Handled = true; } diff --git a/Source/CSharpDemos/CalendarBrowser/CalendarObjectDlg.cs b/Source/CSharpDemos/CalendarBrowser/CalendarObjectDlg.cs index 7a71c3c..d4fb270 100644 --- a/Source/CSharpDemos/CalendarBrowser/CalendarObjectDlg.cs +++ b/Source/CSharpDemos/CalendarBrowser/CalendarObjectDlg.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : CalendarObjectDlg.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a calendar object's properties (VEvent, VToDo, or a VJournal component) // @@ -60,7 +60,7 @@ public CalendarObjectDlg() cboTimeZone.Items.Add("No time zone"); foreach(VTimeZone tz in VCalendar.TimeZones) - cboTimeZone.Items.Add(tz.TimeZoneId.Value); + cboTimeZone.Items.Add(tz.TimeZoneId.Value!); cboTimeZone.SelectedIndex = 0; } @@ -75,7 +75,7 @@ public CalendarObjectDlg() /// The calendar object from which to get the settings public void SetValues(CalendarObject oCal) { - string timeZoneId = null; + string? timeZoneId = null; bool isICalendar = (oCal?.Version == SpecificationVersions.iCalendar20); // Disable controls that aren't relevant to the vCalendar spec @@ -125,7 +125,7 @@ public void SetValues(CalendarObject oCal) txtDescription.Text = e.Description.Value; // Load status values and set status - cboStatus.Items.AddRange(new[] { "None", "Tentative", "Confirmed", "Cancelled" }); + cboStatus.Items.AddRange(["None", "Tentative", "Confirmed", "Cancelled"]); if(!cboStatus.Items.Contains(e.Status.StatusValue.ToString())) cboStatus.Items.Add(e.Status.StatusValue.ToString()); @@ -217,7 +217,7 @@ public void SetValues(CalendarObject oCal) txtDescription.Text = td.Description.Value; // Load status values and set status - cboStatus.Items.AddRange(new[] { "None", "NeedsAction", "Completed", "InProcess", "Cancelled" }); + cboStatus.Items.AddRange(["None", "NeedsAction", "Completed", "InProcess", "Cancelled"]); if(!cboStatus.Items.Contains(td.Status.StatusValue.ToString())) cboStatus.Items.Add(td.Status.StatusValue.ToString()); @@ -290,7 +290,7 @@ public void SetValues(CalendarObject oCal) txtDescription.Text = j.Description.Value; // Load status values and set status - cboStatus.Items.AddRange(new[] { "None", "Draft", "Final", "Cancelled" }); + cboStatus.Items.AddRange(["None", "Draft", "Final", "Cancelled"]); if(!cboStatus.Items.Contains(j.Status.StatusValue.ToString())) cboStatus.Items.Add(j.Status.StatusValue.ToString()); @@ -378,7 +378,7 @@ public void GetValues(CalendarObject oCal) // Get status value e.Status.StatusValue = (StatusValue)Enum.Parse(typeof(StatusValue), - cboStatus.Items[cboStatus.SelectedIndex].ToString(), true); + cboStatus.Items[cboStatus.SelectedIndex]!.ToString()!, true); // We'll edit categories and resources as comma separated strings e.Categories.CategoriesString = txtCategories.Text; @@ -459,7 +459,7 @@ public void GetValues(CalendarObject oCal) // Get status value td.Status.StatusValue = (StatusValue)Enum.Parse(typeof(StatusValue), - cboStatus.Items[cboStatus.SelectedIndex].ToString(), true); + cboStatus.Items[cboStatus.SelectedIndex]!.ToString()!, true); // We'll edit categories and resources as comma separated strings td.Categories.CategoriesString = txtCategories.Text; @@ -521,7 +521,7 @@ public void GetValues(CalendarObject oCal) // Get status value j.Status.StatusValue = (StatusValue)Enum.Parse(typeof(StatusValue), - cboStatus.Items[cboStatus.SelectedIndex].ToString(), true); + cboStatus.Items[cboStatus.SelectedIndex]!.ToString()!, true); // We'll edit categories as a comma separated string j.Categories.CategoriesString = txtCategories.Text; @@ -580,7 +580,7 @@ private void cboTimeZone_SelectedIndexChanged(object sender, EventArgs e) private void btnApplyTZ_Click(object sender, EventArgs e) { DateTimeInstance dti; - string sourceTZ, destTZ; + string? sourceTZ, destTZ; if(cboTimeZone.SelectedIndex == timeZoneIdx) { @@ -600,9 +600,9 @@ private void btnApplyTZ_Click(object sender, EventArgs e) if(timeZoneIdx == 0) sourceTZ = null; else - sourceTZ = (string)cboTimeZone.Items[timeZoneIdx]; + sourceTZ = (string?)cboTimeZone.Items[timeZoneIdx]; - destTZ = (string)cboTimeZone.Items[cboTimeZone.SelectedIndex]; + destTZ = (string?)cboTimeZone.Items[cboTimeZone.SelectedIndex]; // Convert the times. Note that the completed date is always in universal time so it isn't touched. if(sourceTZ == null) @@ -684,6 +684,7 @@ private void CalendarObjectDlg_Closing(object sender, CancelEventArgs e) tabInfo.SelectedTab = pgGeneral; if(txtDuration.Visible && txtDuration.Text.Length != 0) + { if(!Duration.TryParse(txtDuration.Text, out Duration d)) { e.Cancel = true; @@ -691,12 +692,15 @@ private void CalendarObjectDlg_Closing(object sender, CancelEventArgs e) txtDuration.Focus(); } else + { if(d != Duration.Zero && dtpEndDate.Visible && dtpEndDate.Checked) { e.Cancel = true; epErrors.SetError(dtpEndDate, "A duration or an end date can be specified, but not both"); dtpEndDate.Focus(); } + } + } if(dtpEndDate.Visible && dtpStartDate.Checked && dtpEndDate.Checked && dtpStartDate.Value > dtpEndDate.Value) { @@ -708,6 +712,7 @@ private void CalendarObjectDlg_Closing(object sender, CancelEventArgs e) if(txtLatitude.Enabled) { if(txtLatitude.Text.Length != 0) + { if(!Double.TryParse(txtLatitude.Text, out double latitude) || latitude < -90.0 || latitude > 90.0) { e.Cancel = true; @@ -715,8 +720,10 @@ private void CalendarObjectDlg_Closing(object sender, CancelEventArgs e) tabInfo.SelectedTab = pgMisc; txtLatitude.Focus(); } + } if(txtLongitude.Text.Length != 0) + { if(!Double.TryParse(txtLongitude.Text, out double longitude) || longitude < -180.0 || longitude > 180.0) { e.Cancel = true; @@ -724,6 +731,7 @@ private void CalendarObjectDlg_Closing(object sender, CancelEventArgs e) tabInfo.SelectedTab = pgMisc; txtLongitude.Focus(); } + } } if(ucRequestStatus.Enabled && !ucRequestStatus.ValidateItems()) diff --git a/Source/CSharpDemos/CalendarBrowser/FreeBusyControl.cs b/Source/CSharpDemos/CalendarBrowser/FreeBusyControl.cs index 3f3ad91..aa6e403 100644 --- a/Source/CSharpDemos/CalendarBrowser/FreeBusyControl.cs +++ b/Source/CSharpDemos/CalendarBrowser/FreeBusyControl.cs @@ -2,9 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : FreeBusyControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/29/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Visual C# +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a free/busy object's free/busy collection // @@ -79,18 +78,18 @@ public override void BindToControls() txtOtherType.DataBindings.Add("Text", this.BindingSource, "OtherType"); // The binding events translate between the index value and the free/busy type - Binding b = new Binding("SelectedIndex", this.BindingSource, "FreeBusyType"); + Binding b = new("SelectedIndex", this.BindingSource, "FreeBusyType"); b.Format += FreeBusyType_Format; b.Parse += FreeBusyType_Parse; cboBusyType.DataBindings.Add(b); // This binding events will take care of values that haven't been set in the date/time controls - b = new Binding("Value", this.BindingSource, "PeriodValue_StartDateTime"); + b = new("Value", this.BindingSource, "PeriodValue_StartDateTime"); b.Format += DateTime_Format; b.Parse += DateTime_Parse; dtpStartDate.DataBindings.Add(b); - b = new Binding("Value", this.BindingSource, "PeriodValue_EndDateTime"); + b = new("Value", this.BindingSource, "PeriodValue_EndDateTime"); b.Format += DateTime_Format; b.Parse += DateTime_Parse; dtpEndDate.DataBindings.Add(b); @@ -115,7 +114,7 @@ public bool ValidateItems() foreach(FreeBusyProperty fb in freebusys) { - if(fb.FreeBusyType == FreeBusyType.Other && fb.OtherType.Trim().Length == 0) + if(fb.FreeBusyType == FreeBusyType.Other && fb.OtherType!.Trim().Length == 0) { this.BindingSource.Position = freebusys.IndexOf(fb); txtOtherType.Focus(); @@ -157,7 +156,7 @@ public bool ValidateItems() /// /// The old time zone's ID /// The new time zone's ID - public void ApplyTimeZone(string oldTZ, string newTZ) + public void ApplyTimeZone(string? oldTZ, string? newTZ) { DateTimeInstance dti; @@ -200,9 +199,9 @@ public void ApplyTimeZone(string oldTZ, string newTZ) /// /// The sender of the event /// The event arguments - private void FreeBusyType_Format(object sender, ConvertEventArgs e) + private void FreeBusyType_Format(object? sender, ConvertEventArgs e) { - e.Value = (int)e.Value; + e.Value = (int)e.Value!; } /// @@ -210,9 +209,9 @@ private void FreeBusyType_Format(object sender, ConvertEventArgs e) /// /// The sender of the event /// The event arguments - private void FreeBusyType_Parse(object sender, ConvertEventArgs e) + private void FreeBusyType_Parse(object? sender, ConvertEventArgs e) { - e.Value = (FreeBusyType)e.Value; + e.Value = (FreeBusyType)e.Value!; } /// @@ -220,10 +219,10 @@ private void FreeBusyType_Parse(object sender, ConvertEventArgs e) /// /// The sender of the event /// The event arguments - private void DateTime_Format(object sender, ConvertEventArgs e) + private void DateTime_Format(object? sender, ConvertEventArgs e) { - DateTimePicker dtp = (DateTimePicker)(((Binding)sender).Control); - DateTime date = (DateTime)e.Value; + DateTimePicker dtp = (DateTimePicker)(((Binding)sender!).Control); + DateTime date = (DateTime)e.Value!; if(date == DateTime.MinValue) { @@ -239,9 +238,9 @@ private void DateTime_Format(object sender, ConvertEventArgs e) /// /// The sender of the event /// The event arguments - void DateTime_Parse(object sender, ConvertEventArgs e) + void DateTime_Parse(object? sender, ConvertEventArgs e) { - DateTimePicker dtp = (DateTimePicker)(((Binding)sender).Control); + DateTimePicker dtp = (DateTimePicker)(((Binding)sender!).Control); if(!dtp.Checked) e.Value = DateTime.MinValue; diff --git a/Source/CSharpDemos/CalendarBrowser/GlobalSuppressions.cs b/Source/CSharpDemos/CalendarBrowser/GlobalSuppressions.cs index 7bf3cf414a86a6fc8f0d136caf82543bbfdae11d..941178c79a4e43aa994aec591794b5dbbfc250cd 100644 GIT binary patch delta 107 zcmdni%-Ge=xM7>)VUwN}wo+2O*0X(iut_av4&=s){EE+O415z%Me{NX2Nf0=oqOcljAe delta 9 QcmeBbXWZ7zxM7 rules = new List - { - new ListItem(ObservanceRuleType.Standard, "Standard"), - new ListItem(ObservanceRuleType.Daylight, "Daylight") - }; + List rules = + [ + new(ObservanceRuleType.Standard, "Standard"), + new(ObservanceRuleType.Daylight, "Daylight") + ]; cboRuleType.ValueMember = "Value"; cboRuleType.DisplayMember = "Display"; @@ -100,7 +99,7 @@ public override void BindToControls() txtComment.DataBindings.Add("Text", this.BindingSource, "Comment_Value"); // We'll use the Format event to set a valid default date - Binding b = new Binding("Value", this.BindingSource, "StartDateTime_TimeZoneDateTime"); + Binding b = new("Value", this.BindingSource, "StartDateTime_TimeZoneDateTime"); b.Format += StartDate_Format; dtpStartDate.DataBindings.Add(b); @@ -167,9 +166,9 @@ private void StoreChanges() /// /// The sender of the event /// The event arguments - private void StartDate_Format(object sender, ConvertEventArgs e) + private void StartDate_Format(object? sender, ConvertEventArgs e) { - DateTime date = (DateTime)e.Value; + DateTime date = (DateTime)e.Value!; if(date < dtpStartDate.MinDate || date > dtpStartDate.MaxDate) e.Value = DateTime.Today; @@ -199,7 +198,7 @@ private void txtTZName_Validating(object sender, CancelEventArgs e) /// The event arguments private void Minutes_Validating(object sender, CancelEventArgs e) { - NumericUpDown udcHours, udcMins = sender as NumericUpDown; + NumericUpDown udcHours, udcMins = (sender as NumericUpDown)!; this.ErrorProvider.Clear(); @@ -222,7 +221,7 @@ private void Minutes_Validating(object sender, CancelEventArgs e) /// /// The sender of the event /// The event arguments - private void BindingSource_PositionChanged(object sender, EventArgs e) + private void BindingSource_PositionChanged(object? sender, EventArgs e) { ObservanceRule newItem = (ObservanceRule)this.BindingSource.Current; int hours, minutes; diff --git a/Source/CSharpDemos/CalendarBrowser/Properties/AssemblyInfoShared.cs b/Source/CSharpDemos/CalendarBrowser/Properties/AssemblyInfoShared.cs index 9bc7f75..9062baf 100644 --- a/Source/CSharpDemos/CalendarBrowser/Properties/AssemblyInfoShared.cs +++ b/Source/CSharpDemos/CalendarBrowser/Properties/AssemblyInfoShared.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : AssemblyInfo.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +// Updated : 01/09/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // PDI library demos common assembly attributes // @@ -27,7 +27,7 @@ // General assembly information [assembly: AssemblyProduct("EWSoftware Personal Data Interchange Library")] [assembly: AssemblyCompany("Eric Woodruff")] -[assembly: AssemblyCopyright("Copyright \xA9 2003-2023, Eric Woodruff, All Rights Reserved")] +[assembly: AssemblyCopyright("Copyright \xA9 2003-2025, Eric Woodruff, All Rights Reserved")] [assembly: AssemblyCulture("")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] @@ -44,7 +44,7 @@ // Resources contained within the assembly are English [assembly: NeutralResourcesLanguage("en")] -#if NET6_0_OR_GREATER +#if NET8_0_OR_GREATER [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows")] #endif @@ -55,5 +55,5 @@ // Day of release // Revision (typically zero unless multiple releases are made on the same day) // -[assembly: AssemblyVersion("2023.1.2.0")] -[assembly: AssemblyFileVersion("23.1.2.0")] +[assembly: AssemblyVersion("2025.1.9.0")] +[assembly: AssemblyFileVersion("25.1.9.0")] diff --git a/Source/CSharpDemos/CalendarBrowser/RecurrenceControl.cs b/Source/CSharpDemos/CalendarBrowser/RecurrenceControl.cs index 2c0a7f7..7893548 100644 --- a/Source/CSharpDemos/CalendarBrowser/RecurrenceControl.cs +++ b/Source/CSharpDemos/CalendarBrowser/RecurrenceControl.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : RecurrenceControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a recurring calendar object's recurrence rule and recurrence date properties // @@ -89,8 +89,8 @@ public RecurrenceControl() CultureInfo.CurrentCulture.DateTimeFormat.LongTimePattern; dtpRDate.Value = DateTime.Today; - rRules = new RRulePropertyCollection(); - rDates = new RDatePropertyCollection(); + rRules = []; + rDates = []; this.SetButtonStates(); } #endregion @@ -162,7 +162,7 @@ public void SetValues(RRulePropertyCollection er, ExDatePropertyCollection ed) // Convert the exception dates to RDate format internally foreach(ExDateProperty edate in ed) { - RDateProperty rd = new RDateProperty + RDateProperty rd = new() { ValueLocation = edate.ValueLocation, TimeZoneId = edate.TimeZoneId, @@ -219,7 +219,7 @@ public void GetValues(RRulePropertyCollection er, ExDatePropertyCollection ed) // Convert the RDates to ExDate format foreach(RDateProperty rdate in rDates) { - ExDateProperty edate = new ExDateProperty + ExDateProperty edate = new() { ValueLocation = rdate.ValueLocation, TimeZoneId = rdate.TimeZoneId, @@ -236,7 +236,7 @@ public void GetValues(RRulePropertyCollection er, ExDatePropertyCollection ed) /// /// The old time zone's ID /// The new time zone's ID - public void ApplyTimeZone(string oldTZ, string newTZ) + public void ApplyTimeZone(string? oldTZ, string? newTZ) { DateTimeInstance dti; int idx = 0; @@ -270,25 +270,24 @@ public void ApplyTimeZone(string oldTZ, string newTZ) /// The event parameters private void btnAddRRule_Click(object sender, EventArgs e) { - using(RecurrencePropertiesDlg dlg = new RecurrencePropertiesDlg()) + using var dlg = new RecurrencePropertiesDlg(); + + if(dlg.ShowDialog() == DialogResult.OK) { - if(dlg.ShowDialog() == DialogResult.OK) + // Add the recurrence rule to the collection and the list box using the appropriate type + if(!editsExceptions) { - // Add the recurrence rule to the collection and the list box using the appropriate type - if(!editsExceptions) - { - RRuleProperty rr = new RRuleProperty(); - dlg.GetRecurrence(rr.Recurrence); - rRules.Add(rr); - lbRRules.Items.Add(rr.Recurrence.ToString()); - } - else - { - ExRuleProperty er = new ExRuleProperty(); - dlg.GetRecurrence(er.Recurrence); - rRules.Add(er); - lbRRules.Items.Add(er.Recurrence.ToString()); - } + RRuleProperty rr = new(); + dlg.GetRecurrence(rr.Recurrence); + rRules.Add(rr); + lbRRules.Items.Add(rr.Recurrence.ToString()); + } + else + { + ExRuleProperty er = new(); + dlg.GetRecurrence(er.Recurrence); + rRules.Add(er); + lbRRules.Items.Add(er.Recurrence.ToString()); } } @@ -308,25 +307,24 @@ private void btnEditRRule_Click(object sender, EventArgs e) return; } - using(RecurrencePropertiesDlg dlg = new RecurrencePropertiesDlg()) + using var dlg = new RecurrencePropertiesDlg(); + + try { - try - { - Recurrence r = rRules[lbRRules.SelectedIndex].Recurrence; - dlg.SetRecurrence(r); - - if(dlg.ShowDialog() == DialogResult.OK) - { - // Update the recurrence rule in the collection and the list box - dlg.GetRecurrence(r); - lbRRules.Items[lbRRules.SelectedIndex] = r.ToString(); - } - } - catch(Exception ex) + Recurrence r = rRules[lbRRules.SelectedIndex].Recurrence; + dlg.SetRecurrence(r); + + if(dlg.ShowDialog() == DialogResult.OK) { - MessageBox.Show(ex.ToString()); + // Update the recurrence rule in the collection and the list box + dlg.GetRecurrence(r); + lbRRules.Items[lbRRules.SelectedIndex] = r.ToString(); } } + catch(Exception ex) + { + MessageBox.Show(ex.ToString()); + } } /// @@ -372,7 +370,7 @@ private void btnAddRDate_Click(object sender, EventArgs e) // time part is omitted. if(chkExcludeDay.Checked) { - RDateProperty rdate = new RDateProperty + RDateProperty rdate = new() { ValueLocation = ValLocValue.Date, TimeZoneDateTime = dtpRDate.Value.Date @@ -383,7 +381,7 @@ private void btnAddRDate_Click(object sender, EventArgs e) } else { - RDateProperty rdate = new RDateProperty { TimeZoneDateTime = dtpRDate.Value }; + RDateProperty rdate = new() { TimeZoneDateTime = dtpRDate.Value }; rDates.Add(rdate); lbRDates.Items.Add(dtpRDate.Value.ToString("G", CultureInfo.CurrentCulture)); diff --git a/Source/CSharpDemos/CalendarBrowser/RequestStatusControl.cs b/Source/CSharpDemos/CalendarBrowser/RequestStatusControl.cs index b97633d..e8c9ba0 100644 --- a/Source/CSharpDemos/CalendarBrowser/RequestStatusControl.cs +++ b/Source/CSharpDemos/CalendarBrowser/RequestStatusControl.cs @@ -2,9 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : RequestStatusControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/29/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Visual C# +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a calendar object's request status collection // @@ -89,6 +88,7 @@ public bool ValidateItems() RequestStatusPropertyCollection requests = (RequestStatusPropertyCollection)this.BindingSource.DataSource; foreach(RequestStatusProperty status in requests) + { if(String.IsNullOrWhiteSpace(status.StatusMessage)) { this.BindingSource.Position = requests.IndexOf(status); @@ -96,6 +96,7 @@ public bool ValidateItems() txtMessage_Validating(txtMessage, new CancelEventArgs()); return false; } + } return true; } diff --git a/Source/CSharpDemos/CalendarBrowser/TimeZoneListDlg.cs b/Source/CSharpDemos/CalendarBrowser/TimeZoneListDlg.cs index 687023e..3728b9c 100644 --- a/Source/CSharpDemos/CalendarBrowser/TimeZoneListDlg.cs +++ b/Source/CSharpDemos/CalendarBrowser/TimeZoneListDlg.cs @@ -2,9 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : TimeZoneListDlg.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/23/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Visual C# +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit view and edit time zones and apply them to the calendar // @@ -31,12 +30,12 @@ namespace CalendarBrowser /// /// This form is used for editing time zone information. /// - public partial class TimeZoneListDlg : System.Windows.Forms.Form + public partial class TimeZoneListDlg : Form { #region Private data members //===================================================================== - private VTimeZoneCollection timeZones; + private readonly VTimeZoneCollection timeZones; #endregion @@ -46,7 +45,7 @@ public partial class TimeZoneListDlg : System.Windows.Forms.Form /// /// Get or set the currently loaded calendar /// - public VCalendar CurrentCalendar { get; set; } + public VCalendar? CurrentCalendar { get; set; } /// /// Set or get the modified state @@ -71,7 +70,7 @@ public TimeZoneListDlg() CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern + " " + CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern; - timeZones = new VTimeZoneCollection(); + timeZones = []; LoadGridWithItems(); } #endregion @@ -93,7 +92,7 @@ private void LoadGridWithItems() if(chkLimitToCalendar.Checked) { // Get just the time zones used - StringCollection timeZonesUsed = new StringCollection(); + StringCollection timeZonesUsed = []; if(this.CurrentCalendar != null) { @@ -101,18 +100,20 @@ private void LoadGridWithItems() // Remove entries that don't exist for(int idx = 0; idx < timeZonesUsed.Count; idx++) + { if(VCalendar.TimeZones[timeZonesUsed[idx]] == null) { timeZonesUsed.RemoveAt(idx); idx--; } + } } // Add each instance to a temporary collection and bind it to the grid timeZones.Clear(); foreach(string timeZoneId in timeZonesUsed) - timeZones.Add(VCalendar.TimeZones[timeZoneId]); + timeZones.Add(VCalendar.TimeZones[timeZoneId]!); dgvCalendar.DataSource = timeZones; } @@ -158,18 +159,17 @@ private void chkLimitToCalendar_CheckedChanged(object sender, EventArgs e) /// The event arguments private void btnAdd_Click(object sender, EventArgs e) { - using(VTimeZoneDlg dlg = new VTimeZoneDlg()) + using var dlg = new VTimeZoneDlg(); + + if(dlg.ShowDialog() == DialogResult.OK) { - if(dlg.ShowDialog() == DialogResult.OK) - { - VTimeZone tz = new VTimeZone(); - dlg.GetValues(tz); + VTimeZone tz = new(); + dlg.GetValues(tz); - VCalendar.TimeZones.Add(tz); + VCalendar.TimeZones.Add(tz); - this.Modified = true; - this.LoadGridWithItems(); - } + this.Modified = true; + this.LoadGridWithItems(); } } @@ -187,18 +187,17 @@ private void btnEdit_Click(object sender, EventArgs e) return; } - using(VTimeZoneDlg dlg = new VTimeZoneDlg()) - { - string timeZoneId = (string)dgvCalendar[0, dgvCalendar.CurrentCellAddress.Y].Value; - dlg.SetValues(VCalendar.TimeZones[timeZoneId]); + using var dlg = new VTimeZoneDlg(); + + string timeZoneId = (string)dgvCalendar[0, dgvCalendar.CurrentCellAddress.Y].Value; + dlg.SetValues(VCalendar.TimeZones[timeZoneId]!); - if(dlg.ShowDialog() == DialogResult.OK) - { - dlg.GetValues(VCalendar.TimeZones[timeZoneId]); + if(dlg.ShowDialog() == DialogResult.OK) + { + dlg.GetValues(VCalendar.TimeZones[timeZoneId]!); - this.Modified = true; - this.LoadGridWithItems(); - } + this.Modified = true; + this.LoadGridWithItems(); } } @@ -216,12 +215,11 @@ private void btnDelete_Click(object sender, EventArgs e) return; } - StringCollection timeZonesUsed = new StringCollection(); + StringCollection timeZonesUsed = []; string timeZoneId = (string)dgvCalendar[0, dgvCalendar.CurrentCellAddress.Y].Value; - if(this.CurrentCalendar != null) - this.CurrentCalendar.TimeZonesUsed(timeZonesUsed); + this.CurrentCalendar?.TimeZonesUsed(timeZonesUsed); if(timeZonesUsed.Contains(timeZoneId)) { @@ -233,7 +231,7 @@ private void btnDelete_Click(object sender, EventArgs e) if(MessageBox.Show("Are you sure you want to delete the selected item?", "Delete Item", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes) { - VCalendar.TimeZones.Remove(VCalendar.TimeZones[timeZoneId]); + VCalendar.TimeZones.Remove(VCalendar.TimeZones[timeZoneId]!); this.Modified = true; this.LoadGridWithItems(); @@ -261,7 +259,7 @@ private void btnApply_Click(object sender, EventArgs e) { string timeZoneId = (string)dgvCalendar[0, dgvCalendar.CurrentCellAddress.Y].Value; - this.CurrentCalendar.ApplyTimeZone(VCalendar.TimeZones[timeZoneId]); + this.CurrentCalendar?.ApplyTimeZone(VCalendar.TimeZones[timeZoneId]); this.Modified = true; } diff --git a/Source/CSharpDemos/CalendarBrowser/VFreeBusyDlg.cs b/Source/CSharpDemos/CalendarBrowser/VFreeBusyDlg.cs index ef87025..7ba4649 100644 --- a/Source/CSharpDemos/CalendarBrowser/VFreeBusyDlg.cs +++ b/Source/CSharpDemos/CalendarBrowser/VFreeBusyDlg.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : VFreeBusyDlg.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a VFreeBusy object's properties // @@ -61,7 +61,7 @@ public VFreeBusyDlg() cboTimeZone.Items.Add("No time zone"); foreach(VTimeZone tz in VCalendar.TimeZones) - cboTimeZone.Items.Add(tz.TimeZoneId.Value); + cboTimeZone.Items.Add(tz.TimeZoneId.Value!); cboTimeZone.SelectedIndex = 0; } @@ -79,7 +79,7 @@ public void SetValues(VFreeBusy fb) if(fb == null) throw new ArgumentNullException(nameof(fb)); - string timeZoneId = fb.StartDateTime.TimeZoneId; + string? timeZoneId = fb.StartDateTime.TimeZoneId; txtUniqueId.Text = fb.UniqueId.Value; txtOrganizer.Text = fb.Organizer.Value; @@ -204,7 +204,7 @@ private void cboTimeZone_SelectedIndexChanged(object sender, EventArgs e) private void btnApplyTZ_Click(object sender, EventArgs e) { DateTimeInstance dti; - string sourceTZ, destTZ; + string? sourceTZ, destTZ; if(cboTimeZone.SelectedIndex == timeZoneIdx) { @@ -224,9 +224,9 @@ private void btnApplyTZ_Click(object sender, EventArgs e) if(timeZoneIdx == 0) sourceTZ = null; else - sourceTZ = (string)cboTimeZone.Items[timeZoneIdx]; + sourceTZ = (string)cboTimeZone.Items[timeZoneIdx]!; - destTZ = (string)cboTimeZone.Items[cboTimeZone.SelectedIndex]; + destTZ = (string)cboTimeZone.Items[cboTimeZone.SelectedIndex]!; // Convert the times if(sourceTZ == null) @@ -299,12 +299,14 @@ private void VFreeBusyDlg_Closing(object sender, CancelEventArgs e) e.Cancel = true; } else + { if(!ucFreeBusy.ValidateItems()) { tabInfo.SelectedTab = pgFreeBusy; ucFreeBusy.Focus(); e.Cancel = true; } + } } #endregion } diff --git a/Source/CSharpDemos/CalendarBrowser/VTimeZoneDlg.cs b/Source/CSharpDemos/CalendarBrowser/VTimeZoneDlg.cs index e8d5814..3dbb956 100644 --- a/Source/CSharpDemos/CalendarBrowser/VTimeZoneDlg.cs +++ b/Source/CSharpDemos/CalendarBrowser/VTimeZoneDlg.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : VTimeZoneDlg.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a VTimeZone object's properties // @@ -35,7 +35,7 @@ public partial class VTimeZoneDlg : System.Windows.Forms.Form #region Private data members //===================================================================== - private string originalId; + private string? originalId; #endregion @@ -119,12 +119,14 @@ private void VTimeZoneDlg_Closing(object sender, CancelEventArgs e) { // Disallow duplicate time zone IDs if(originalId == null || txtTimeZoneId.Text != originalId) + { if(VCalendar.TimeZones[txtTimeZoneId.Text] != null) { epErrors.SetError(txtTimeZoneId, "A time zone with the specified ID already exists"); e.Cancel = true; txtTimeZoneId.Focus(); } + } } } #endregion diff --git a/Source/CSharpDemos/CalendarBrowser/app.config b/Source/CSharpDemos/CalendarBrowser/app.config index 75f0734..e1665fe 100644 --- a/Source/CSharpDemos/CalendarBrowser/app.config +++ b/Source/CSharpDemos/CalendarBrowser/app.config @@ -1,8 +1,5 @@ - - - diff --git a/Source/CSharpDemos/CalendarBrowser/app.manifest b/Source/CSharpDemos/CalendarBrowser/app.manifest deleted file mode 100644 index aa947e8..0000000 --- a/Source/CSharpDemos/CalendarBrowser/app.manifest +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Source/CSharpDemos/PDIDatesTest/PDIDatesTest.cs b/Source/CSharpDemos/PDIDatesTest/PDIDatesTest.cs index 363738d..cfedf10 100644 --- a/Source/CSharpDemos/PDIDatesTest/PDIDatesTest.cs +++ b/Source/CSharpDemos/PDIDatesTest/PDIDatesTest.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : PDIDatesTest.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2003-2023, Eric Woodruff, All rights reserved +// Updated : 01/04/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This is a console mode application that runs through a few simple configurations to test the basics in the // date utility, holiday, and recurrence classes. @@ -31,7 +31,7 @@ namespace PDIDatesTest /// /// A simple test of the EWSoftware.PDI date and recurrence classes /// - class PDIDatesTest + sealed class PDIDatesTest { /// /// This is used to test the EWSoftware.PDI namespace date utility and recurrence classes. It displays @@ -87,17 +87,17 @@ static void Main(string[] args) } // Test DateUtils.CalculateOccurrenceDate - Console.WriteLine("Fourth weekday in January 2018: {0:d}", - DateUtils.CalculateOccurrenceDate(2018, 1, DayOccurrence.Fourth, DaysOfWeek.Weekdays, 0)); + Console.WriteLine("Fourth weekday in January {0}: {1:d}", yearFrom, + DateUtils.CalculateOccurrenceDate(yearFrom, 1, DayOccurrence.Fourth, DaysOfWeek.Weekdays, 0)); - Console.WriteLine("Fourth weekday in January 2018 + 2: {0:d}", - DateUtils.CalculateOccurrenceDate(2018, 1, DayOccurrence.Fourth, DaysOfWeek.Weekdays, 2)); + Console.WriteLine("Fourth weekday in January {0} + 2: {1:d}", yearFrom, + DateUtils.CalculateOccurrenceDate(yearFrom, 1, DayOccurrence.Fourth, DaysOfWeek.Weekdays, 2)); - Console.WriteLine("Last weekend day in January 2018: {0:d}", - DateUtils.CalculateOccurrenceDate(2018, 1, DayOccurrence.Last, DaysOfWeek.Weekends, 0)); + Console.WriteLine("Last weekend day in January {0}: {1:d}", yearFrom, + DateUtils.CalculateOccurrenceDate(yearFrom, 1, DayOccurrence.Last, DaysOfWeek.Weekends, 0)); - Console.WriteLine("Last weekend day in January 2018 + 2: {0:d}", - DateUtils.CalculateOccurrenceDate(2018, 1, DayOccurrence.Last, DaysOfWeek.Weekends, 2)); + Console.WriteLine("Last weekend day in January {0} + 2: {1:d}", yearFrom, + DateUtils.CalculateOccurrenceDate(yearFrom, 1, DayOccurrence.Last, DaysOfWeek.Weekends, 2)); // Pause to review output Console.WriteLine("Press ENTER to continue"); @@ -113,6 +113,7 @@ static void Main(string[] args) for(year = yearFrom; year <= yearTo; year++) { for(idx = 1; idx < 54; idx++) + { if(idx != 53 || DateUtils.WeeksInYear(year, dow) == 53) { weekFrom = DateUtils.DateFromWeek(year, idx, dow, 0); @@ -121,6 +122,7 @@ static void Main(string[] args) Console.WriteLine("{0} Week {1}: {2:d} - {3:d} {4}", year, idx, weekFrom, weekTo, DateUtils.WeekFromDate(weekFrom.AddDays(3), dow)); } + } // Pause to review output Console.WriteLine("Press ENTER to continue"); @@ -268,7 +270,7 @@ static void Main(string[] args) Console.WriteLine("Assumptions: 1 year = {0} days, 1 month = {1} days\n", Duration.DaysInOneYear, Duration.DaysInOneMonth); - Duration d = new Duration("P1Y2M3W4DT5H6M7S"); + Duration d = new("P1Y2M3W4DT5H6M7S"); Console.WriteLine("P1Y2M3W4DT5H6M7S = {0}", d.ToString()); Console.WriteLine("P1Y2M3W4DT5H6M7S = {0} (max units = months)", d.ToString(Duration.MaxUnit.Months)); @@ -522,7 +524,7 @@ static void Main(string[] args) Console.ReadLine(); // Create a set of fixed and floating holidays - HolidayCollection holidays = new HolidayCollection(); + HolidayCollection? holidays = []; holidays.AddFixed(1, 1, true, "New Year's Day"); holidays.AddFloating(DayOccurrence.Third, DayOfWeek.Monday, 1, 0, "Martin Luther King Day"); @@ -542,7 +544,7 @@ static void Main(string[] args) // XML using(var fs = new FileStream("Holidays.xml", FileMode.Create)) { - XmlSerializer xs = new XmlSerializer(typeof(HolidayCollection)); + var xs = new XmlSerializer(typeof(HolidayCollection)); xs.Serialize(fs, holidays); Console.WriteLine("Holidays saved to Holidays.xml"); @@ -591,8 +593,8 @@ static void Main(string[] args) // XML using(var fs = new FileStream("Holidays.xml", FileMode.Open)) { - XmlSerializer xs = new XmlSerializer(typeof(HolidayCollection)); - holidays = (HolidayCollection)xs.Deserialize(fs); + var xs = new XmlSerializer(typeof(HolidayCollection)); + holidays = (HolidayCollection?)xs.Deserialize(fs); Console.WriteLine("Holidays retrieved from Holidays.xml"); } @@ -634,9 +636,11 @@ static void Main(string[] args) // Display the holidays added to the list Console.WriteLine("Holidays on file. Is Holiday should be true for all."); - foreach(Holiday hol in holidays) + foreach(Holiday hol in holidays!) + { Console.WriteLine("Holiday Date: {0:d} Is Holiday: {1} Description: {2}", hol.ToDateTime(yearFrom), holidays.IsHoliday(hol.ToDateTime(yearFrom)), hol.Description); + } // Pause to review output Console.WriteLine("Press ENTER to continue"); @@ -691,7 +695,7 @@ static void Main(string[] args) //================================================================= // Test recurrence - Recurrence rRecur = new Recurrence(); + Recurrence? rRecur = new(); Recurrence.Holidays.AddRange(holidays); // Disallow occurrences on any of the defined holidays @@ -710,7 +714,7 @@ static void Main(string[] args) // XML using(var fs = new FileStream("Recurrence.xml", FileMode.Create)) { - XmlSerializer xs = new XmlSerializer(typeof(Recurrence)); + var xs = new XmlSerializer(typeof(Recurrence)); xs.Serialize(fs, rRecur); Console.WriteLine("Recurrence saved to Recurrence.xml"); @@ -756,8 +760,8 @@ static void Main(string[] args) // XML using(var fs = new FileStream("Recurrence.xml", FileMode.Open)) { - XmlSerializer xs = new XmlSerializer(typeof(Recurrence)); - rRecur = (Recurrence)xs.Deserialize(fs); + var xs = new XmlSerializer(typeof(Recurrence)); + rRecur = (Recurrence?)xs.Deserialize(fs); Console.WriteLine("Recurrence restored from Recurrence.xml"); } @@ -794,7 +798,7 @@ static void Main(string[] args) } } - recurDates = rRecur.InstancesBetween(testDate, testDate.AddMonths(1)); + recurDates = rRecur!.InstancesBetween(testDate, testDate.AddMonths(1)); Console.WriteLine(rRecur.ToStringWithStartDateTime()); diff --git a/Source/CSharpDemos/PDIDatesTest/PDIDatesTest.csproj b/Source/CSharpDemos/PDIDatesTest/PDIDatesTest.csproj index 130174a..d4ee563 100644 --- a/Source/CSharpDemos/PDIDatesTest/PDIDatesTest.csproj +++ b/Source/CSharpDemos/PDIDatesTest/PDIDatesTest.csproj @@ -1,30 +1,32 @@  - - Exe - net6.0;net40 - False - False - False - False - False - False - ProductAttribute - PDIDatesTest.snk - true - true - AllEnabledByDefault - + + Exe + net8.0;net40 + False + False + False + False + False + False + ProductAttribute + PDIDatesTest.snk + true + true + AllEnabledByDefault + latest + enable + - - - + + + - - - + + + - - - + + + diff --git a/Source/CSharpDemos/PDIParserTest/PDIParserTest.cs b/Source/CSharpDemos/PDIParserTest/PDIParserTest.cs index 27fb736..5761b59 100644 --- a/Source/CSharpDemos/PDIParserTest/PDIParserTest.cs +++ b/Source/CSharpDemos/PDIParserTest/PDIParserTest.cs @@ -2,9 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : PDIParserTest.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/19/2018 -// Note : Copyright 2003-2018, Eric Woodruff, All rights reserved -// Compiler: Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This is just a quick test of the PDI vCard and calendar parser classes in a console mode application // @@ -33,7 +32,7 @@ namespace PDIParserTest /// /// A simple test of the EWSoftware.PDI Personal Data Interchange classes /// - class PDIParserTest + sealed class PDIParserTest { /// /// This is used to test the EWSoftware.PDI.Data namespace Personal Data Interchange classes. It scans @@ -50,7 +49,7 @@ static void Main(string[] args) if(args.Length != 2) { Console.WriteLine("Using files from .\\PDIFiles for the test\r\n"); - args = new[] { @"..\..\..\..\..\..\PDIFiles", @"..\..\..\..\..\..\PDIFiles_Copy" }; + args = [@"..\..\..\..\..\..\PDIFiles", @"..\..\..\..\..\..\PDIFiles_Copy"]; } try @@ -71,7 +70,7 @@ static void Main(string[] args) // Since we'll be parsing multiple files, we'll create an instance of the parser and re-use it // rather than using the static parsing methods. - VCardParser vcardp = new VCardParser(); + VCardParser vcardp = new(); foreach(string file in Directory.EnumerateFiles(args[0], "*.vcf")) { @@ -98,7 +97,7 @@ static void Main(string[] args) // Since we'll be parsing multiple files, we'll create an instance of the parser and re-use it // rather than using the static parser methods. - VCalendarParser vcalp = new VCalendarParser(); + VCalendarParser vcalp = new(); foreach(string file in Directory.EnumerateFiles(args[0], "*.vcs")) { @@ -106,7 +105,7 @@ static void Main(string[] args) vcalp.ParseFile(file); - Console.WriteLine(vcalp.VCalendar.ToString()); + Console.WriteLine(vcalp.VCalendar!.ToString()); // Write it to a stream outputFile = outputFolder + Path.GetFileName(file); @@ -130,7 +129,7 @@ static void Main(string[] args) vcalp.ParseFile(file); - Console.WriteLine(vcalp.VCalendar.ToString()); + Console.WriteLine(vcalp.VCalendar!.ToString()); // Write it to a stream outputFile = outputFolder + Path.GetFileName(file); @@ -149,7 +148,7 @@ static void Main(string[] args) // Since we'll be parsing multiple files, we'll create an instance of the parser and re-use it // rather than using the static parser methods. - VNoteParser vnp = new VNoteParser(); + VNoteParser vnp = new(); foreach(string file in Directory.EnumerateFiles(args[0], "*.vnt")) { diff --git a/Source/CSharpDemos/PDIParserTest/PDIParserTest.csproj b/Source/CSharpDemos/PDIParserTest/PDIParserTest.csproj index ca8c068..4cf3b67 100644 --- a/Source/CSharpDemos/PDIParserTest/PDIParserTest.csproj +++ b/Source/CSharpDemos/PDIParserTest/PDIParserTest.csproj @@ -1,28 +1,30 @@  - - Exe - net6.0;net40 - False - False - False - False - False - False - ProductAttribute - PDIParserTest.snk - true - true - AllEnabledByDefault - + + Exe + net8.0;net40 + False + False + False + False + False + False + ProductAttribute + PDIParserTest.snk + true + true + AllEnabledByDefault + latest + enable + - - - + + + - - - - + + + + diff --git a/Source/CSharpDemos/PDIWebDemoCS/Web.config b/Source/CSharpDemos/PDIWebDemoCS/Web.config index 028459a..912dbbb 100644 --- a/Source/CSharpDemos/PDIWebDemoCS/Web.config +++ b/Source/CSharpDemos/PDIWebDemoCS/Web.config @@ -24,7 +24,7 @@ - + diff --git a/Source/CSharpDemos/PDIWinFormsTest/AboutDlg.cs b/Source/CSharpDemos/PDIWinFormsTest/AboutDlg.cs index 83c01ca..229ee35 100644 --- a/Source/CSharpDemos/PDIWinFormsTest/AboutDlg.cs +++ b/Source/CSharpDemos/PDIWinFormsTest/AboutDlg.cs @@ -1,9 +1,8 @@ //=============================================================================================================== // File : AboutDlg.cs // Author : Eric Woodruff -// Updated : 11/23/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This form is used to display application version information // @@ -50,13 +49,13 @@ public AboutDlg() private void AboutDlg_Load(object sender, EventArgs e) { // Get assembly information not available from the application object - Assembly asm = Assembly.GetEntryAssembly(); + Assembly asm = Assembly.GetEntryAssembly()!; AssemblyTitleAttribute title = (AssemblyTitleAttribute) - AssemblyTitleAttribute.GetCustomAttribute(asm, typeof(AssemblyTitleAttribute)); + Attribute.GetCustomAttribute(asm, typeof(AssemblyTitleAttribute))!; AssemblyCopyrightAttribute copyright = (AssemblyCopyrightAttribute) - AssemblyCopyrightAttribute.GetCustomAttribute(asm, typeof(AssemblyCopyrightAttribute)); + Attribute.GetCustomAttribute(asm, typeof(AssemblyCopyrightAttribute))!; AssemblyDescriptionAttribute desc = (AssemblyDescriptionAttribute) - AssemblyDescriptionAttribute.GetCustomAttribute(asm, typeof(AssemblyDescriptionAttribute)); + Attribute.GetCustomAttribute(asm, typeof(AssemblyDescriptionAttribute))!; // Set the labels lblName.Text = title.Title; @@ -68,7 +67,7 @@ private void AboutDlg_Load(object sender, EventArgs e) foreach(AssemblyName an in asm.GetReferencedAssemblies()) { ListViewItem lvi = lvComponents.Items.Add(an.Name); - lvi.SubItems.Add(an.Version.ToString()); + lvi.SubItems.Add(an.Version!.ToString()); } lvComponents.Sorting = SortOrder.Ascending; @@ -109,7 +108,7 @@ private void lnkHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) try { // Launch the e-mail URL, this will fail if user does not have an association for e-mail URLs - System.Diagnostics.Process.Start((string)e.Link.LinkData); + System.Diagnostics.Process.Start((string)e.Link!.LinkData!); } catch(Exception ex) { diff --git a/Source/CSharpDemos/PDIWinFormsTest/EventRecurTestForm.cs b/Source/CSharpDemos/PDIWinFormsTest/EventRecurTestForm.cs index a577c1c..a42c629 100644 --- a/Source/CSharpDemos/PDIWinFormsTest/EventRecurTestForm.cs +++ b/Source/CSharpDemos/PDIWinFormsTest/EventRecurTestForm.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : EventRecurTestForm.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2003-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This is a simple demonstration used to test the event recurrence generation features of the calendar classes // @@ -67,11 +67,11 @@ private void EventRecurTestForm_Load(object sender, EventArgs e) cboTimeZone.Items.Add("No time zone"); foreach(VTimeZone vtz in VCalendar.TimeZones) - cboTimeZone.Items.Add(vtz.TimeZoneId.Value); + cboTimeZone.Items.Add(vtz.TimeZoneId.Value!); cboTimeZone.SelectedIndex = 0; - DateTime dtDate = new DateTime(DateTime.Today.Year, 1, 1); + DateTime dtDate = new(DateTime.Today.Year, 1, 1); dtpStartDate.Value = dtDate; dtpEndDate.Value = dtDate.AddMonths(3); @@ -102,7 +102,7 @@ private void EventRecurTestForm_Closing(object sender, CancelEventArgs e) /// The event arguments private void btnTest_Click(object sender, EventArgs e) { - RecurringObject ro = null; + RecurringObject? ro = null; DateTimeInstanceCollection instances; string calendar; int start; @@ -121,11 +121,15 @@ private void btnTest_Click(object sender, EventArgs e) if(cal.Events.Count > 0) ro = cal.Events[0]; else + { if(cal.ToDos.Count > 0) ro = cal.ToDos[0]; else + { if(cal.Journals.Count > 0) ro = cal.Journals[0]; + } + } if(ro == null) { diff --git a/Source/CSharpDemos/PDIWinFormsTest/HolidayTestForm.cs b/Source/CSharpDemos/PDIWinFormsTest/HolidayTestForm.cs index 07d5082..470d544 100644 --- a/Source/CSharpDemos/PDIWinFormsTest/HolidayTestForm.cs +++ b/Source/CSharpDemos/PDIWinFormsTest/HolidayTestForm.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : HolidayTestForm.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2021 -// Note : Copyright 2003-2021, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This is used to test the various Holiday classes and the DateUtils class // @@ -45,8 +45,8 @@ public HolidayTestForm() dgvDatesFound.AutoGenerateColumns = false; tbcDate.DefaultCellStyle.Format = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern; - hmHolidays.Defaults = hmHolidays.Defaults.Concat(new[] { - new FixedHoliday(6, 19, true, "Juneteenth") { MinimumYear = 2021 } }).OrderBy(h => h.Month).ToList(); + hmHolidays.Defaults = [.. hmHolidays.Defaults.Concat( + [new FixedHoliday(6, 19, true, "Juneteenth") { MinimumYear = 2021 }]).OrderBy(h => h.Month)]; // Use the standard set of holidays by default. The holiday manager control will make a copy of the // collection and will take care of adding, editing, and deleting entries from it. If an existing @@ -70,7 +70,7 @@ public HolidayTestForm() /// The event arguments private void btnTestDate_Click(object sender, EventArgs e) { - HolidayCollection holidays = new HolidayCollection(hmHolidays.Holidays); + var holidays = new HolidayCollection(hmHolidays.Holidays); if(holidays.IsHoliday(dtpTestDate.Value)) { @@ -78,8 +78,10 @@ private void btnTestDate_Click(object sender, EventArgs e) MessageBoxIcon.Information); } else + { MessageBox.Show("The test date is not a holiday", "Not Found!", MessageBoxButtons.OK, MessageBoxIcon.Information); + } } /// @@ -90,7 +92,7 @@ private void btnTestDate_Click(object sender, EventArgs e) /// The event arguments private void btnFind_Click(object sender, EventArgs e) { - HolidayCollection holidays = new HolidayCollection(hmHolidays.Holidays); + var holidays = new HolidayCollection(hmHolidays.Holidays); int fromYear, toYear, year; fromYear = (int)udcFromYear.Value; @@ -173,7 +175,7 @@ private void btnEaster_Click(object sender, EventArgs e) this.Cursor = Cursors.WaitCursor; // Create the grid view's data source - List items = new List(); + List items = []; desc = $"Easter ({em})"; while(fromYear <= toYear) diff --git a/Source/CSharpDemos/PDIWinFormsTest/MainForm.cs b/Source/CSharpDemos/PDIWinFormsTest/MainForm.cs index 0b3ecfc..a1d4b39 100644 --- a/Source/CSharpDemos/PDIWinFormsTest/MainForm.cs +++ b/Source/CSharpDemos/PDIWinFormsTest/MainForm.cs @@ -2,9 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : MainForm.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/24/2014 -// Note : Copyright 2003-2014, Eric Woodruff, All rights reserved -// Compiler: Visual C# +// Updated : 01/05/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This application is used to demonstrate various features of the EWSoftware PDI classes // @@ -75,10 +74,9 @@ private void btnExit_Click(object sender, EventArgs e) /// The event arguments private void btnHolidays_Click(object sender, EventArgs e) { - using(HolidayTestForm dlg = new HolidayTestForm()) - { - dlg.ShowDialog(); - } + using var dlg = new HolidayTestForm(); + + dlg.ShowDialog(); } /// @@ -88,10 +86,9 @@ private void btnHolidays_Click(object sender, EventArgs e) /// The event arguments private void btnRRULE_Click(object sender, EventArgs e) { - using(RRuleTestForm dlg = new RRuleTestForm()) - { - dlg.ShowDialog(); - } + using var dlg = new RRuleTestForm(); + + dlg.ShowDialog(); } /// @@ -101,10 +98,9 @@ private void btnRRULE_Click(object sender, EventArgs e) /// The event arguments private void btnTestCalRecur_Click(object sender, EventArgs e) { - using(EventRecurTestForm dlg = new EventRecurTestForm()) - { - dlg.ShowDialog(); - } + using var dlg = new EventRecurTestForm(); + + dlg.ShowDialog(); } /// @@ -114,10 +110,9 @@ private void btnTestCalRecur_Click(object sender, EventArgs e) /// The event arguments private void btnTestVTimeZone_Click(object sender, EventArgs e) { - using(VTimeZoneTestForm dlg = new VTimeZoneTestForm()) - { - dlg.ShowDialog(); - } + using var dlg = new VTimeZoneTestForm(); + + dlg.ShowDialog(); } /// @@ -127,10 +122,9 @@ private void btnTestVTimeZone_Click(object sender, EventArgs e) /// The event arguments private void btnAbout_Click(object sender, EventArgs e) { - using(AboutDlg dlg = new AboutDlg()) - { - dlg.ShowDialog(); - } + using var dlg = new AboutDlg(); + + dlg.ShowDialog(); } #endregion } diff --git a/Source/CSharpDemos/PDIWinFormsTest/PDIWinFormsTest.csproj b/Source/CSharpDemos/PDIWinFormsTest/PDIWinFormsTest.csproj index 062c9f8..89c3ae2 100644 --- a/Source/CSharpDemos/PDIWinFormsTest/PDIWinFormsTest.csproj +++ b/Source/CSharpDemos/PDIWinFormsTest/PDIWinFormsTest.csproj @@ -1,26 +1,28 @@  - - WinExe - net6.0-windows;net40 - true - False - False - False - False - False - False - ProductAttribute - PDIWinFormsTest.snk - true - true - AllEnabledByDefault - - - - - - - - - + + WinExe + net8.0-windows;net40 + true + False + False + False + False + False + False + ProductAttribute + PDIWinFormsTest.snk + true + true + AllEnabledByDefault + latest + enable + + + + + + + + + \ No newline at end of file diff --git a/Source/CSharpDemos/PDIWinFormsTest/RRuleTestForm.cs b/Source/CSharpDemos/PDIWinFormsTest/RRuleTestForm.cs index dbccd14..c14d50b 100644 --- a/Source/CSharpDemos/PDIWinFormsTest/RRuleTestForm.cs +++ b/Source/CSharpDemos/PDIWinFormsTest/RRuleTestForm.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : RRuleTestForm.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2003-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This is a simple demonstration used to test the recurrence engine which encapsulates the iCalendar 2.0 RRULE // feature set. It is separate from the other PDI calendar classes so that you can use the recurrence engine @@ -75,7 +75,7 @@ private void btnTest_Click(object sender, EventArgs e) lblCount.Text = String.Empty; // Define the recurrence rule by parsing the text - Recurrence r = new Recurrence(txtRRULE.Text) { StartDateTime = dtpStartDate.Value }; + var r = new Recurrence(txtRRULE.Text) { StartDateTime = dtpStartDate.Value }; // Get the currently defined set of holidays if necessary if(!r.CanOccurOnHoliday) @@ -87,16 +87,20 @@ private void btnTest_Click(object sender, EventArgs e) // For hourly, minutely, and secondly, warn the user if there is no end date or max occurrences if(r.Frequency >= RecurFrequency.Hourly && r.MaximumOccurrences == 0 && r.RecurUntil > r.StartDateTime.AddDays(100)) + { if(MessageBox.Show("This recurrence may run for a very long time. Continue?", "Confirm", MessageBoxButtons.YesNo) == DialogResult.No) + { return; + } + } lbDates.DataSource = null; this.Cursor = Cursors.WaitCursor; - start = System.Environment.TickCount; + start = Environment.TickCount; dc = r.InstancesBetween(r.StartDateTime, DateTime.MaxValue); - elapsed = (System.Environment.TickCount - start) / 1000.0; + elapsed = (Environment.TickCount - start) / 1000.0; count = dc.Count; if(count > 5000) @@ -155,25 +159,24 @@ private void RRuleTestForm_Closed(object sender, EventArgs e) /// The event arguments private void btnDesign_Click(object sender, EventArgs e) { - using(RecurrencePropertiesDlg dlg = new RecurrencePropertiesDlg()) + using var dlg = new RecurrencePropertiesDlg(); + + try { - try - { - Recurrence r = new Recurrence(txtRRULE.Text) { StartDateTime = dtpStartDate.Value }; + var r = new Recurrence(txtRRULE.Text) { StartDateTime = dtpStartDate.Value }; - dlg.SetRecurrence(r); + dlg.SetRecurrence(r); - if(dlg.ShowDialog() == DialogResult.OK) - { - dlg.GetRecurrence(r); - txtRRULE.Text = r.ToString(); - } - } - catch(Exception ex) + if(dlg.ShowDialog() == DialogResult.OK) { - MessageBox.Show(ex.ToString()); + dlg.GetRecurrence(r); + txtRRULE.Text = r.ToString(); } } + catch(Exception ex) + { + MessageBox.Show(ex.ToString()); + } } /// @@ -185,7 +188,7 @@ private void btnDescribe_Click(object sender, EventArgs e) { try { - Recurrence r = new Recurrence(txtRRULE.Text); + var r = new Recurrence(txtRRULE.Text); MessageBox.Show(r.ToDescription(), "Recurrence Description"); } catch(Exception ex) diff --git a/Source/CSharpDemos/PDIWinFormsTest/TimeZoneRegInfo.cs b/Source/CSharpDemos/PDIWinFormsTest/TimeZoneRegInfo.cs index c13a379..197d568 100644 --- a/Source/CSharpDemos/PDIWinFormsTest/TimeZoneRegInfo.cs +++ b/Source/CSharpDemos/PDIWinFormsTest/TimeZoneRegInfo.cs @@ -2,9 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : TimeZoneRegInfo.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/23/2018 -// Note : Copyright 2003-2018, Eric Woodruff, All rights reserved -// Compiler: Visual C# +// Updated : 01/05/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This class is used to create a time zone information from the time zone data found in the registry on Windows // PCs. @@ -123,7 +122,7 @@ public static TIMEZONE FromRegistry(object timeZoneInfo) Marshal.Copy(tziBytes, 0, buffer, size); - tzi = (TIMEZONE)Marshal.PtrToStructure(buffer, typeof(TIMEZONE)); + tzi = (TIMEZONE)Marshal.PtrToStructure(buffer, typeof(TIMEZONE))!; } finally { @@ -144,7 +143,7 @@ public static TIMEZONE FromRegistry(object timeZoneInfo) /// public static void LoadTimeZoneInfo() { - string keyName, display, standardDesc, dstDesc; + string? keyName, display, standardDesc, dstDesc; TIMEZONE tz; VCalendar.TimeZones.Clear(); @@ -157,86 +156,93 @@ public static void LoadTimeZoneInfo() else keyName = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"; - using(var rk = Registry.LocalMachine.OpenSubKey(keyName)) + using var rk = Registry.LocalMachine.OpenSubKey(keyName); + + if(rk == null) + return; + + foreach(string s in rk.GetSubKeyNames()) { - foreach(string s in rk.GetSubKeyNames()) + using var rsk = rk.OpenSubKey(s); + + var t = rsk?.GetValue("TZI"); + + if(t == null) + continue; + + display = (string)rsk!.GetValue("Display")!; + standardDesc = (string)rsk.GetValue("Std")!; + dstDesc = (string)rsk.GetValue("Dlt")!; + + tz = TIMEZONE.FromRegistry(t); + + // Create the time zone object + VTimeZone vtz = new(); + vtz.TimeZoneId.Value = display; + + ObservanceRule or = vtz.ObservanceRules.Add(ObservanceRuleType.Standard); + + or.OffsetFrom.TimeSpanValue = TimeSpan.FromMinutes(tz.nBias + tz.nDaylightBias).Negate(); + or.OffsetTo.TimeSpanValue = TimeSpan.FromMinutes(tz.nBias + tz.nStandardBias).Negate(); + or.TimeZoneNames.Add(standardDesc); + + // If the standard date month is zero, it doesn't use standard time. Assume 01/01/1970 and + // set it up to return the offset. + if(tz.standardDate.wMonth == 0) + or.StartDateTime.DateTimeValue = new DateTime(1970, 1, 1); + else { - using(var rsk = rk.OpenSubKey(s)) + // If year is zero, its a recurrence. If not zero, it's a fixed date. + if(tz.standardDate.wYear == 0) { - display = (string)rsk.GetValue("Display"); - standardDesc = (string)rsk.GetValue("Std"); - dstDesc = (string)rsk.GetValue("Dlt"); - tz = TIMEZONE.FromRegistry(rsk.GetValue("TZI")); - } - - // Create the time zone object - VTimeZone vtz = new VTimeZone(); - vtz.TimeZoneId.Value = display; + or.StartDateTime.DateTimeValue = tz.standardDate.ToDateTime(1970); - ObservanceRule or = vtz.ObservanceRules.Add(ObservanceRuleType.Standard); + RRuleProperty rrule = new(); - or.OffsetFrom.TimeSpanValue = TimeSpan.FromMinutes(tz.nBias + tz.nDaylightBias).Negate(); - or.OffsetTo.TimeSpanValue = TimeSpan.FromMinutes(tz.nBias + tz.nStandardBias).Negate(); - or.TimeZoneNames.Add(standardDesc); + rrule.Recurrence.RecurYearly( + (tz.standardDate.wDay > 4) ? DayOccurrence.Last : (DayOccurrence)tz.standardDate.wDay, + tz.standardDate.DayOfWeek(), tz.standardDate.wMonth, 1); - // If the standard date month is zero, it doesn't use standard time. Assume 01/01/1970 and - // set it up to return the offset. - if(tz.standardDate.wMonth == 0) - or.StartDateTime.DateTimeValue = new DateTime(1970, 1, 1); + or.RecurrenceRules.Add(rrule); + } else { - // If year is zero, its a recurrence. If not zero, it's a fixed date. - if(tz.standardDate.wYear == 0) - { - or.StartDateTime.DateTimeValue = tz.standardDate.ToDateTime(1970); - - RRuleProperty rrule = new RRuleProperty(); - - rrule.Recurrence.RecurYearly( - (tz.standardDate.wDay > 4) ? DayOccurrence.Last : (DayOccurrence)tz.standardDate.wDay, - tz.standardDate.DayOfWeek(), tz.standardDate.wMonth, 1); - - or.RecurrenceRules.Add(rrule); - } - else - { - or.StartDateTime.DateTimeValue = tz.standardDate.ToDateTime(); - or.RecurDates.Add(or.StartDateTime.DateTimeValue); - } + or.StartDateTime.DateTimeValue = tz.standardDate.ToDateTime(); + or.RecurDates.Add(or.StartDateTime.DateTimeValue); } + } + + // If the daylight month is zero, it doesn't use DST. The standard rule will handle + // everything. + if(tz.daylightDate.wMonth != 0) + { + or = vtz.ObservanceRules.Add(ObservanceRuleType.Daylight); - // If the daylight month is zero, it doesn't use DST. The standard rule will handle - // everything. - if(tz.daylightDate.wMonth != 0) + or.OffsetFrom.TimeSpanValue = TimeSpan.FromMinutes(tz.nBias + tz.nStandardBias).Negate(); + or.OffsetTo.TimeSpanValue = TimeSpan.FromMinutes(tz.nBias + tz.nDaylightBias).Negate(); + or.TimeZoneNames.Add(dstDesc); + + // If year is zero, its a recurrence. If not zero, it's a fixed date. + if(tz.daylightDate.wYear == 0) { - or = vtz.ObservanceRules.Add(ObservanceRuleType.Daylight); - - or.OffsetFrom.TimeSpanValue = TimeSpan.FromMinutes(tz.nBias + tz.nStandardBias).Negate(); - or.OffsetTo.TimeSpanValue = TimeSpan.FromMinutes(tz.nBias + tz.nDaylightBias).Negate(); - or.TimeZoneNames.Add(dstDesc); - - // If year is zero, its a recurrence. If not zero, it's a fixed date. - if(tz.daylightDate.wYear == 0) - { - or.StartDateTime.DateTimeValue = tz.daylightDate.ToDateTime(1970); - - RRuleProperty rrule = new RRuleProperty(); - - rrule.Recurrence.RecurYearly( - (tz.daylightDate.wDay > 4) ? DayOccurrence.Last : (DayOccurrence)tz.daylightDate.wDay, - tz.daylightDate.DayOfWeek(), tz.daylightDate.wMonth, 1); - - or.RecurrenceRules.Add(rrule); - } - else - { - or.StartDateTime.DateTimeValue = tz.daylightDate.ToDateTime(); - or.RecurDates.Add(or.StartDateTime.DateTimeValue); - } - } + or.StartDateTime.DateTimeValue = tz.daylightDate.ToDateTime(1970); + + RRuleProperty rrule = new(); - VCalendar.TimeZones.Add(vtz); + rrule.Recurrence.RecurYearly( + (tz.daylightDate.wDay > 4) ? DayOccurrence.Last : (DayOccurrence)tz.daylightDate.wDay, + tz.daylightDate.DayOfWeek(), tz.daylightDate.wMonth, 1); + + or.RecurrenceRules.Add(rrule); + } + else + { + or.StartDateTime.DateTimeValue = tz.daylightDate.ToDateTime(); + or.RecurDates.Add(or.StartDateTime.DateTimeValue); + } } + + VCalendar.TimeZones.Add(vtz); } // Put the time zones in sorted order diff --git a/Source/CSharpDemos/PDIWinFormsTest/VTimeZoneTestForm.cs b/Source/CSharpDemos/PDIWinFormsTest/VTimeZoneTestForm.cs index 9c0b60b..c3dfe2c 100644 --- a/Source/CSharpDemos/PDIWinFormsTest/VTimeZoneTestForm.cs +++ b/Source/CSharpDemos/PDIWinFormsTest/VTimeZoneTestForm.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : VTimeZoneTestForm.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2003-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This is a simple demonstration used to test the EWSoftware PDI time zone classes and methods. This // demonstration depends on the time zone information present in the Windows registry. @@ -138,56 +138,54 @@ private void UpdateTimes(object sender, EventArgs e) /// The event arguments private void btnSaveTZs_Click(object sender, EventArgs e) { - using(SaveFileDialog dlg = new SaveFileDialog()) + using var dlg = new SaveFileDialog(); + + dlg.Title = "Save Time Zone Database"; + dlg.Filter = "ICS files (*.ics)|*.ics|All files (*.*)|*.*"; + dlg.DefaultExt = "ics"; + dlg.FilterIndex = 1; + dlg.InitialDirectory = Environment.CurrentDirectory; + dlg.FileName = "TimeZoneDB.ics"; + + if(dlg.ShowDialog() == DialogResult.OK) { - dlg.Title = "Save Time Zone Database"; - dlg.Filter = "ICS files (*.ics)|*.ics|All files (*.*)|*.*"; - dlg.DefaultExt = "ics"; - dlg.FilterIndex = 1; - dlg.InitialDirectory = Environment.CurrentDirectory; - dlg.FileName = "TimeZoneDB.ics"; - - if(dlg.ShowDialog() == DialogResult.OK) + try { - try - { - this.Cursor = Cursors.WaitCursor; - - // Open the file and write the time zone data to it - using(var sw = new StreamWriter(dlg.FileName)) - { - // Since we are writing out the time zone collection by itself, we'll need to provide - // the calender wrapper. - sw.WriteLine("BEGIN:VCALENDAR"); - sw.WriteLine("VERSION:2.0"); - sw.WriteLine("PRODID:-//EWSoftware//PDI Class Library//EN"); - - foreach(VTimeZone tz in VCalendar.TimeZones) - tz.WriteToStream(sw); - - sw.WriteLine("END:VCALENDAR"); - } - } - catch(Exception ex) - { - string errorMsg = $"Unable to save time zone info:\n{ex.Message}"; + this.Cursor = Cursors.WaitCursor; - if(ex.InnerException != null) - { - errorMsg += ex.InnerException.Message + "\n"; + // Open the file and write the time zone data to it + using var sw = new StreamWriter(dlg.FileName); + + // Since we are writing out the time zone collection by itself, we'll need to provide + // the calender wrapper. + sw.WriteLine("BEGIN:VCALENDAR"); + sw.WriteLine("VERSION:2.0"); + sw.WriteLine("PRODID:-//EWSoftware//PDI Class Library//EN"); - if(ex.InnerException.InnerException != null) - errorMsg += ex.InnerException.InnerException.Message; - } + foreach(VTimeZone tz in VCalendar.TimeZones) + tz.WriteToStream(sw); - System.Diagnostics.Debug.Write(ex); + sw.WriteLine("END:VCALENDAR"); + } + catch(Exception ex) + { + string errorMsg = $"Unable to save time zone info:\n{ex.Message}"; - MessageBox.Show(errorMsg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - finally + if(ex.InnerException != null) { - this.Cursor = Cursors.Default; + errorMsg += ex.InnerException.Message + "\n"; + + if(ex.InnerException.InnerException != null) + errorMsg += ex.InnerException.InnerException.Message; } + + System.Diagnostics.Debug.Write(ex); + + MessageBox.Show(errorMsg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + this.Cursor = Cursors.Default; } } } diff --git a/Source/CSharpDemos/PDIWinFormsTest/app.config b/Source/CSharpDemos/PDIWinFormsTest/app.config index 047b3b0..0f7eeef 100644 --- a/Source/CSharpDemos/PDIWinFormsTest/app.config +++ b/Source/CSharpDemos/PDIWinFormsTest/app.config @@ -1,8 +1,5 @@ - - - diff --git a/Source/CSharpDemos/PDIWinFormsTest/app.manifest b/Source/CSharpDemos/PDIWinFormsTest/app.manifest deleted file mode 100644 index e0f5061..0000000 --- a/Source/CSharpDemos/PDIWinFormsTest/app.manifest +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Source/CSharpDemos/RFC2445RecurTest/RFC2445RecurTest.cs b/Source/CSharpDemos/RFC2445RecurTest/RFC2445RecurTest.cs index 1833a28..e6cd879 100644 --- a/Source/CSharpDemos/RFC2445RecurTest/RFC2445RecurTest.cs +++ b/Source/CSharpDemos/RFC2445RecurTest/RFC2445RecurTest.cs @@ -2,9 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : RFC2445RecurTest.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/20/2018 -// Note : Copyright 2003-2018, Eric Woodruff, All rights reserved -// Compiler: Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This creates the example recurrence patterns given in the RFC 2445 iCalendar specification starting on page // 118 and generates the instances for each one. Rather than parsing the information from strings, it shows how @@ -20,6 +19,8 @@ // 10/22/2004 EFW Created the code //=============================================================================================================== +#pragma warning disable CA1861 + using System; using EWSoftware.PDI; @@ -31,7 +32,7 @@ namespace RFC2445RecurTest /// /// Test the various RFC 2445 iCalendar recurrence patterns found in the spec starting on page 118 /// - class RFC2445RecurTest + sealed class RFC2445RecurTest { /// /// Create each pattern using the API and generate the instances. @@ -39,7 +40,7 @@ class RFC2445RecurTest [STAThread] static void Main() { - Recurrence r = new Recurrence(); + Recurrence r = new(); int idx; Console.WriteLine("The first part will calculate instances using only the Recurrence class. All " + @@ -137,8 +138,8 @@ static void Main() // When adding days without an instance value, you can use the helper method on the collection that // takes an array of DayOfWeek values rather than constructing an array of DayInstance objects. - r.ByDay.AddRange(new[] { DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, - DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Saturday }); + r.ByDay.AddRange([ DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, + DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Saturday ]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -229,7 +230,7 @@ static void Main() r.Frequency = RecurFrequency.Weekly; r.RecurUntil = new DateTime(1997, 10, 07, 0, 0, 0); r.WeekStart = DayOfWeek.Sunday; - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Thursday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Thursday]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -249,7 +250,7 @@ static void Main() r.Frequency = RecurFrequency.Weekly; r.MaximumOccurrences = 10; r.WeekStart = DayOfWeek.Sunday; - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Thursday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Thursday]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -273,7 +274,7 @@ static void Main() r.Interval = 2; r.WeekStart = DayOfWeek.Sunday; r.RecurUntil = new DateTime(1997, 12, 24, 0, 0, 0); - r.ByDay.AddRange(new[] { DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday }); + r.ByDay.AddRange([DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -293,7 +294,7 @@ static void Main() r.Interval = 2; r.WeekStart = DayOfWeek.Sunday; r.MaximumOccurrences = 8; - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Thursday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Thursday]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -350,7 +351,7 @@ static void Main() r.Frequency = RecurFrequency.Monthly; r.Interval = 2; r.MaximumOccurrences = 10; - r.ByDay.AddRange(new[] { new DayInstance(1, DayOfWeek.Sunday), new DayInstance(-1, DayOfWeek.Sunday) }); + r.ByDay.AddRange([new DayInstance(1, DayOfWeek.Sunday), new DayInstance(-1, DayOfWeek.Sunday)]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -404,7 +405,7 @@ static void Main() r.StartDateTime = new DateTime(1997, 9, 2, 9, 0, 0); r.Frequency = RecurFrequency.Monthly; r.MaximumOccurrences = 10; - r.ByMonthDay.AddRange(new[] { 2, 15 }); + r.ByMonthDay.AddRange([2, 15]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -422,7 +423,7 @@ static void Main() r.StartDateTime = new DateTime(1997, 9, 30, 9, 0, 0); r.Frequency = RecurFrequency.Monthly; r.MaximumOccurrences = 10; - r.ByMonthDay.AddRange(new[] { 1, -1 }); + r.ByMonthDay.AddRange([1, -1]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -441,7 +442,7 @@ static void Main() r.Frequency = RecurFrequency.Monthly; r.Interval = 18; r.MaximumOccurrences = 10; - r.ByMonthDay.AddRange(new[] { 10, 11, 12, 13, 14, 15 }); + r.ByMonthDay.AddRange([10, 11, 12, 13, 14, 15]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -478,7 +479,7 @@ static void Main() r.StartDateTime = new DateTime(1997, 6, 10, 9, 0, 0); r.Frequency = RecurFrequency.Yearly; r.MaximumOccurrences = 10; - r.ByMonth.AddRange(new[] { 6, 7 }); + r.ByMonth.AddRange([6, 7]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -497,7 +498,7 @@ static void Main() r.Frequency = RecurFrequency.Yearly; r.Interval = 2; r.MaximumOccurrences = 10; - r.ByMonth.AddRange(new[] { 1, 2, 3 }); + r.ByMonth.AddRange([1, 2, 3]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -516,7 +517,7 @@ static void Main() r.Frequency = RecurFrequency.Yearly; r.Interval = 3; r.MaximumOccurrences = 10; - r.ByYearDay.AddRange(new[] { 1, 100, 200 }); + r.ByYearDay.AddRange([1, 100, 200]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -589,7 +590,7 @@ static void Main() r.Reset(); r.StartDateTime = new DateTime(1997, 6, 5, 9, 0, 0); r.Frequency = RecurFrequency.Yearly; - r.ByMonth.AddRange(new[] { 6, 7, 8 }); + r.ByMonth.AddRange([6, 7, 8]); r.ByDay.Add(DayOfWeek.Thursday); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -628,7 +629,7 @@ static void Main() r.StartDateTime = new DateTime(1997, 9, 13, 9, 0, 0); r.Frequency = RecurFrequency.Monthly; r.ByDay.Add(DayOfWeek.Saturday); - r.ByMonthDay.AddRange(new[] { 7, 8, 9, 10, 11, 12, 13 }); + r.ByMonthDay.AddRange([7, 8, 9, 10, 11, 12, 13]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -650,7 +651,7 @@ static void Main() r.Interval = 4; r.ByMonth.Add(11); r.ByDay.Add(DayOfWeek.Tuesday); - r.ByMonthDay.AddRange(new[] { 2, 3, 4, 5, 6, 7, 8 }); + r.ByMonthDay.AddRange([2, 3, 4, 5, 6, 7, 8]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -671,7 +672,7 @@ static void Main() r.Frequency = RecurFrequency.Monthly; r.MaximumOccurrences = 3; r.BySetPos.Add(3); - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -689,8 +690,8 @@ static void Main() r.StartDateTime = new DateTime(1997, 9, 29, 9, 0, 0); r.Frequency = RecurFrequency.Monthly; r.BySetPos.Add(-2); - r.ByDay.AddRange(new[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, - DayOfWeek.Thursday, DayOfWeek.Friday }); + r.ByDay.AddRange([ DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, + DayOfWeek.Thursday, DayOfWeek.Friday ]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -762,8 +763,8 @@ static void Main() r.Reset(); r.StartDateTime = new DateTime(1997, 9, 2, 9, 0, 0); r.Frequency = RecurFrequency.Daily; - r.ByHour.AddRange(new[] { 9, 10, 11, 12, 13, 14, 15, 16 }); - r.ByMinute.AddRange( new[] { 0, 20, 40 }); + r.ByHour.AddRange([9, 10, 11, 12, 13, 14, 15, 16]); + r.ByMinute.AddRange([0, 20, 40]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -783,7 +784,7 @@ static void Main() r.StartDateTime = new DateTime(1997, 9, 2, 9, 0, 0); r.Frequency = RecurFrequency.Minutely; r.Interval = 20; - r.ByHour.AddRange(new[] { 9, 10, 11, 12, 13, 14, 15, 16 }); + r.ByHour.AddRange([9, 10, 11, 12, 13, 14, 15, 16]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -803,7 +804,7 @@ static void Main() r.Frequency = RecurFrequency.Weekly; r.Interval = 2; r.MaximumOccurrences = 4; - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Sunday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Sunday]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -823,7 +824,7 @@ static void Main() r.Interval = 2; r.MaximumOccurrences = 4; r.WeekStart = DayOfWeek.Sunday; - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Sunday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Sunday]); Console.WriteLine(r.ToStringWithStartDateTime()); @@ -842,7 +843,7 @@ static void Main() // First, set up the time zone information. If you don't care about the time zone, you can skip this // stuff and everything will be calculated in local time. - VTimeZone vtz = new VTimeZone(); + VTimeZone vtz = new(); vtz.TimeZoneId.Value = "US-Eastern"; // Set the standard time observance rule @@ -852,7 +853,7 @@ static void Main() obr.OffsetFrom.TimeSpanValue = TimeSpan.FromHours(-4); obr.OffsetTo.TimeSpanValue = TimeSpan.FromHours(-5); - RRuleProperty rrule = new RRuleProperty(); + RRuleProperty rrule = new(); rrule.Recurrence.RecurYearly(DayOccurrence.Last, DaysOfWeek.Sunday, 10, 1); obr.RecurrenceRules.Add(rrule); @@ -875,7 +876,7 @@ static void Main() // Now we'll set up an event to use for the calculations. We don't need a VCalendar object as we are // just generating recurring instances. - VEvent vevent = new VEvent(); + VEvent vevent = new(); // Add an RRULE property rrule = new RRuleProperty(); @@ -1015,8 +1016,8 @@ static void Main() // When adding days without an instance value, you can use the helper method on the collection that // takes an array of DayOfWeek values rather than constructing an array of DayInstance objects. - r.ByDay.AddRange(new[] { DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, - DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Saturday }); + r.ByDay.AddRange([ DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, + DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Saturday ]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1138,7 +1139,7 @@ static void Main() r.Frequency = RecurFrequency.Weekly; r.RecurUntil = new DateTime(1997, 10, 07, 4, 0, 0).ToLocalTime(); r.WeekStart = DayOfWeek.Sunday; - r.ByDay.AddRange(new [] { DayOfWeek.Tuesday, DayOfWeek.Thursday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Thursday]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1164,7 +1165,7 @@ static void Main() r.Frequency = RecurFrequency.Weekly; r.MaximumOccurrences = 10; r.WeekStart = DayOfWeek.Sunday; - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Thursday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Thursday]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1193,7 +1194,7 @@ static void Main() r.Interval = 2; r.WeekStart = DayOfWeek.Sunday; r.RecurUntil = new DateTime(1997, 12, 24, 5, 0, 0).ToLocalTime(); - r.ByDay.AddRange(new[] { DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday }); + r.ByDay.AddRange([DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1219,7 +1220,7 @@ static void Main() r.Interval = 2; r.WeekStart = DayOfWeek.Sunday; r.MaximumOccurrences = 8; - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Thursday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Thursday]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1294,7 +1295,7 @@ static void Main() r.Frequency = RecurFrequency.Monthly; r.Interval = 2; r.MaximumOccurrences = 10; - r.ByDay.AddRange(new[] { new DayInstance(1, DayOfWeek.Sunday), new DayInstance(-1, DayOfWeek.Sunday) }); + r.ByDay.AddRange([new DayInstance(1, DayOfWeek.Sunday), new DayInstance(-1, DayOfWeek.Sunday)]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1367,7 +1368,7 @@ static void Main() startDateTime.TimeZoneDateTime = new DateTime(1997, 9, 2, 9, 0, 0); r.Frequency = RecurFrequency.Monthly; r.MaximumOccurrences = 10; - r.ByMonthDay.AddRange(new[] { 2, 15 }); + r.ByMonthDay.AddRange([2, 15]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1391,7 +1392,7 @@ static void Main() startDateTime.TimeZoneDateTime = new DateTime(1997, 9, 30, 9, 0, 0); r.Frequency = RecurFrequency.Monthly; r.MaximumOccurrences = 10; - r.ByMonthDay.AddRange(new[] { 1, -1 }); + r.ByMonthDay.AddRange([1, -1]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1416,7 +1417,7 @@ static void Main() r.Frequency = RecurFrequency.Monthly; r.Interval = 18; r.MaximumOccurrences = 10; - r.ByMonthDay.AddRange(new[] { 10, 11, 12, 13, 14, 15 }); + r.ByMonthDay.AddRange([10, 11, 12, 13, 14, 15]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1466,7 +1467,7 @@ static void Main() startDateTime.TimeZoneDateTime = new DateTime(1997, 6, 10, 9, 0, 0); r.Frequency = RecurFrequency.Yearly; r.MaximumOccurrences = 10; - r.ByMonth.AddRange(new[] { 6, 7 }); + r.ByMonth.AddRange([6, 7]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1491,7 +1492,7 @@ static void Main() r.Frequency = RecurFrequency.Yearly; r.Interval = 2; r.MaximumOccurrences = 10; - r.ByMonth.AddRange(new[] { 1, 2, 3 }); + r.ByMonth.AddRange([1, 2, 3]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1516,7 +1517,7 @@ static void Main() r.Frequency = RecurFrequency.Yearly; r.Interval = 3; r.MaximumOccurrences = 10; - r.ByYearDay.AddRange(new[] { 1, 100, 200 }); + r.ByYearDay.AddRange([1, 100, 200]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1615,7 +1616,7 @@ static void Main() r.Reset(); startDateTime.TimeZoneDateTime = new DateTime(1997, 6, 5, 9, 0, 0); r.Frequency = RecurFrequency.Yearly; - r.ByMonth.AddRange(new[] { 6, 7, 8 }); + r.ByMonth.AddRange([6, 7, 8]); r.ByDay.Add(DayOfWeek.Thursday); // Not forever for the test @@ -1676,7 +1677,7 @@ static void Main() startDateTime.TimeZoneDateTime = new DateTime(1997, 9, 13, 9, 0, 0); r.Frequency = RecurFrequency.Monthly; r.ByDay.Add(DayOfWeek.Saturday); - r.ByMonthDay.AddRange(new[] { 7, 8, 9, 10, 11, 12, 13 }); + r.ByMonthDay.AddRange([7, 8, 9, 10, 11, 12, 13]); // Not forever for the test dtiTZ = vevent.InstancesBetween(startDateTime.TimeZoneDateTime, new DateTime(1998, 7, 1), false); @@ -1705,7 +1706,7 @@ static void Main() r.Interval = 4; r.ByMonth.Add(11); r.ByDay.Add(DayOfWeek.Tuesday); - r.ByMonthDay.AddRange(new[] { 2, 3, 4, 5, 6, 7, 8 }); + r.ByMonthDay.AddRange([2, 3, 4, 5, 6, 7, 8]); // Not forever for the test dtiTZ = vevent.InstancesBetween(startDateTime.TimeZoneDateTime, new DateTime(2004, 11, 3), false); @@ -1733,7 +1734,7 @@ static void Main() r.Frequency = RecurFrequency.Monthly; r.MaximumOccurrences = 3; r.BySetPos.Add(3); - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1757,8 +1758,8 @@ static void Main() startDateTime.TimeZoneDateTime = new DateTime(1997, 9, 29, 9, 0, 0); r.Frequency = RecurFrequency.Monthly; r.BySetPos.Add(-2); - r.ByDay.AddRange(new[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, - DayOfWeek.Thursday, DayOfWeek.Friday }); + r.ByDay.AddRange([ DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, + DayOfWeek.Thursday, DayOfWeek.Friday ]); // Not forever for the test dtiTZ = vevent.InstancesBetween(startDateTime.TimeZoneDateTime, new DateTime(1998, 9, 29), false); @@ -1855,8 +1856,8 @@ static void Main() r.Reset(); startDateTime.TimeZoneDateTime = new DateTime(1997, 9, 2, 9, 0, 0); r.Frequency = RecurFrequency.Daily; - r.ByHour.AddRange(new[] { 9, 10, 11, 12, 13, 14, 15, 16 }); - r.ByMinute.AddRange( new[] { 0, 20, 40 }); + r.ByHour.AddRange([9, 10, 11, 12, 13, 14, 15, 16]); + r.ByMinute.AddRange([0, 20, 40]); // Not forever for the test dtiTZ = vevent.InstancesBetween(startDateTime.TimeZoneDateTime, new DateTime(1997, 9, 4), false); @@ -1883,7 +1884,7 @@ static void Main() startDateTime.TimeZoneDateTime = new DateTime(1997, 9, 2, 9, 0, 0); r.Frequency = RecurFrequency.Minutely; r.Interval = 20; - r.ByHour.AddRange(new[] { 9, 10, 11, 12, 13, 14, 15, 16 }); + r.ByHour.AddRange([9, 10, 11, 12, 13, 14, 15, 16]); // Not forever for the test dtiTZ = vevent.InstancesBetween(startDateTime.TimeZoneDateTime, new DateTime(1997, 9, 4), false); @@ -1910,7 +1911,7 @@ static void Main() r.Frequency = RecurFrequency.Weekly; r.Interval = 2; r.MaximumOccurrences = 4; - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Sunday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Sunday]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); @@ -1936,7 +1937,7 @@ static void Main() r.Interval = 2; r.MaximumOccurrences = 4; r.WeekStart = DayOfWeek.Sunday; - r.ByDay.AddRange(new[] { DayOfWeek.Tuesday, DayOfWeek.Sunday }); + r.ByDay.AddRange([DayOfWeek.Tuesday, DayOfWeek.Sunday]); dtiTZ = vevent.AllInstances(false); dtiLocal = vevent.AllInstances(true); diff --git a/Source/CSharpDemos/RFC2445RecurTest/RFC2445RecurTest.csproj b/Source/CSharpDemos/RFC2445RecurTest/RFC2445RecurTest.csproj index 5df1d83..76f341a 100644 --- a/Source/CSharpDemos/RFC2445RecurTest/RFC2445RecurTest.csproj +++ b/Source/CSharpDemos/RFC2445RecurTest/RFC2445RecurTest.csproj @@ -1,28 +1,30 @@  - - Exe - net6.0;net40 - False - False - False - False - False - False - ProductAttribute - RFC2445RecurTest.snk - true - true - AllEnabledByDefault - + + Exe + net8.0;net40 + False + False + False + False + False + False + ProductAttribute + RFC2445RecurTest.snk + true + true + AllEnabledByDefault + latest + enable + - - - + + + - - - - + + + + diff --git a/Source/CSharpDemos/vCardBrowser/AboutDlg.cs b/Source/CSharpDemos/vCardBrowser/AboutDlg.cs index 2ab1cbb..c707fc0 100644 --- a/Source/CSharpDemos/vCardBrowser/AboutDlg.cs +++ b/Source/CSharpDemos/vCardBrowser/AboutDlg.cs @@ -1,9 +1,8 @@ //=============================================================================================================== // File : AboutDlg.cs // Author : Eric Woodruff -// Updated : 11/23/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This form is used to display application version information // @@ -25,7 +24,7 @@ namespace vCardBrowser { - public partial class AboutDlg : System.Windows.Forms.Form + public partial class AboutDlg : Form { #region Constructor //===================================================================== @@ -50,13 +49,13 @@ public AboutDlg() private void AboutDlg_Load(object sender, EventArgs e) { // Get assembly information not available from the application object - Assembly asm = Assembly.GetEntryAssembly(); + Assembly asm = Assembly.GetEntryAssembly()!; AssemblyTitleAttribute title = (AssemblyTitleAttribute) - AssemblyTitleAttribute.GetCustomAttribute(asm, typeof(AssemblyTitleAttribute)); + Attribute.GetCustomAttribute(asm, typeof(AssemblyTitleAttribute))!; AssemblyCopyrightAttribute copyright = (AssemblyCopyrightAttribute) - AssemblyCopyrightAttribute.GetCustomAttribute(asm, typeof(AssemblyCopyrightAttribute)); + Attribute.GetCustomAttribute(asm, typeof(AssemblyCopyrightAttribute))!; AssemblyDescriptionAttribute desc = (AssemblyDescriptionAttribute) - AssemblyDescriptionAttribute.GetCustomAttribute(asm, typeof(AssemblyDescriptionAttribute)); + Attribute.GetCustomAttribute(asm, typeof(AssemblyDescriptionAttribute))!; // Set the labels lblName.Text = title.Title; @@ -68,7 +67,7 @@ private void AboutDlg_Load(object sender, EventArgs e) foreach(AssemblyName an in asm.GetReferencedAssemblies()) { ListViewItem lvi = lvComponents.Items.Add(an.Name); - lvi.SubItems.Add(an.Version.ToString()); + lvi.SubItems.Add(an.Version!.ToString()); } lvComponents.Sorting = SortOrder.Ascending; @@ -109,7 +108,11 @@ private void lnkHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) try { // Launch the e-mail URL, this will fail if user does not have an association for e-mail URLs - System.Diagnostics.Process.Start((string)e.Link.LinkData); + System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo + { + FileName = (string)e.Link!.LinkData!, + UseShellExecute = true, + }); } catch(Exception ex) { diff --git a/Source/CSharpDemos/vCardBrowser/AddressControl.cs b/Source/CSharpDemos/vCardBrowser/AddressControl.cs index ecc5ef9..947ffb4 100644 --- a/Source/CSharpDemos/vCardBrowser/AddressControl.cs +++ b/Source/CSharpDemos/vCardBrowser/AddressControl.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : AddressControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2020 -// Note : Copyright 2004-2020, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a vCard's address information. It's nothing elaborate but does let you edit the // collection fairly well. @@ -21,6 +21,7 @@ using System; using System.ComponentModel; +using System.Security.Policy; using System.Text; using System.Web; using System.Windows.Forms; @@ -94,43 +95,43 @@ public override void BindToControls() txtCountry.DataBindings.Add("Text", this.BindingSource, "Country"); // For the checkboxes, the Format and Parse events are needed to get and set the checked state - Binding b = new Binding("Checked", this.BindingSource, "AddressTypes"); + Binding b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkDomestic.Tag = AddressTypes.Domestic; chkDomestic.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkInternational.Tag = AddressTypes.International; chkInternational.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkPostal.Tag = AddressTypes.Postal; chkPostal.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkParcel.Tag = AddressTypes.Parcel; chkParcel.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkHome.Tag = AddressTypes.Home; chkHome.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkWork.Tag = AddressTypes.Work; chkWork.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkPreferred.Tag = AddressTypes.Preferred; @@ -146,11 +147,11 @@ public override void BindToControls() /// /// The sender of the event /// The event arguments - private void CheckBox_Format(object sender, ConvertEventArgs e) + private void CheckBox_Format(object? sender, ConvertEventArgs e) { - CheckBox cb = (CheckBox)((Binding)sender).Control; - AddressTypes checkType = (AddressTypes)cb.Tag; - AddressTypes addrTypes = (AddressTypes)e.Value; + CheckBox cb = (CheckBox)((Binding)sender!).Control; + AddressTypes checkType = (AddressTypes)cb.Tag!; + AddressTypes addrTypes = (AddressTypes)e.Value!; e.Value = (addrTypes & checkType) == checkType; } @@ -160,11 +161,11 @@ private void CheckBox_Format(object sender, ConvertEventArgs e) /// /// The sender of the event /// The event arguments - private void CheckBox_Parse(object sender, ConvertEventArgs e) + private void CheckBox_Parse(object? sender, ConvertEventArgs e) { AddressProperty a = (AddressProperty)this.BindingSource.Current; - CheckBox cb = (CheckBox)((Binding)sender).Control; - AddressTypes checkType = (AddressTypes)cb.Tag; + CheckBox cb = (CheckBox)((Binding)sender!).Control; + AddressTypes checkType = (AddressTypes)cb.Tag!; if(cb.Checked) a.AddressTypes |= checkType; @@ -199,7 +200,7 @@ private void txtStreetAddress_Validating(object sender, CancelEventArgs e) /// The event arguments private void btnMap_Click(object sender, EventArgs e) { - StringBuilder sb = new StringBuilder("https://www.google.com/maps/place/", 512); + StringBuilder sb = new("https://www.google.com/maps/place/", 512); if(txtStreetAddress.Text.Length != 0) { @@ -227,7 +228,11 @@ private void btnMap_Click(object sender, EventArgs e) try { - System.Diagnostics.Process.Start(sb.ToString()); + System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo + { + FileName = sb.ToString(), + UseShellExecute = true, + }); } catch(Exception ex) { diff --git a/Source/CSharpDemos/vCardBrowser/EMailControl.cs b/Source/CSharpDemos/vCardBrowser/EMailControl.cs index 50e9b72..cff1a2b 100644 --- a/Source/CSharpDemos/vCardBrowser/EMailControl.cs +++ b/Source/CSharpDemos/vCardBrowser/EMailControl.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : EMailControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/01/2020 -// Note : Copyright 2004-2020, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a vCard's e-mail address information. It's nothing elaborate but does let you edit the // collection fairly well. @@ -35,7 +35,7 @@ public partial class EMailControl : EWSoftware.PDI.Windows.Forms.BrowseControl #region Private data members //===================================================================== - private static Regex reEMailAddress = new Regex(@"^([a-z0-9_\-])([a-z0-9_\-\.]*)@" + + private static readonly Regex reEMailAddress = new(@"^([a-z0-9_\-])([a-z0-9_\-\.]*)@" + @"(\[((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}|((([a-z0-9\-]+)\.)+))([a-z]" + @"{2,}|(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\])$", RegexOptions.IgnoreCase); @@ -96,25 +96,25 @@ public override void BindToControls() // For the checkboxes, the Format and Parse events are needed to get and set the checked state. We // aren't going to check for all of the older less common ones. - Binding b = new Binding("Checked", this.BindingSource, "EMailTypes"); + Binding b = new("Checked", this.BindingSource, "EMailTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkAOL.Tag = EMailTypes.AOL; chkAOL.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "EMailTypes"); + b = new("Checked", this.BindingSource, "EMailTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkInternet.Tag = EMailTypes.Internet; chkInternet.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "EMailTypes"); + b = new("Checked", this.BindingSource, "EMailTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkX400.Tag = EMailTypes.X400; chkX400.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "EMailTypes"); + b = new("Checked", this.BindingSource, "EMailTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkPreferred.Tag = EMailTypes.Preferred; @@ -130,11 +130,11 @@ public override void BindToControls() /// /// The sender of the event /// The event arguments - private void CheckBox_Format(object sender, ConvertEventArgs e) + private void CheckBox_Format(object? sender, ConvertEventArgs e) { - CheckBox cb = (CheckBox)((Binding)sender).Control; - EMailTypes checkType = (EMailTypes)cb.Tag; - EMailTypes emailTypes = (EMailTypes)e.Value; + CheckBox cb = (CheckBox)((Binding)sender!).Control; + EMailTypes checkType = (EMailTypes)cb.Tag!; + EMailTypes emailTypes = (EMailTypes)e.Value!; e.Value = (emailTypes & checkType) == checkType; } @@ -144,11 +144,11 @@ private void CheckBox_Format(object sender, ConvertEventArgs e) /// /// The sender of the event /// The event arguments - private void CheckBox_Parse(object sender, ConvertEventArgs e) + private void CheckBox_Parse(object? sender, ConvertEventArgs e) { EMailProperty email = (EMailProperty)this.BindingSource.Current; - CheckBox cb = (CheckBox)((Binding)sender).Control; - EMailTypes checkType = (EMailTypes)cb.Tag; + CheckBox cb = (CheckBox)((Binding)sender!).Control; + EMailTypes checkType = (EMailTypes)cb.Tag!; if(cb.Checked) email.EMailTypes |= checkType; diff --git a/Source/CSharpDemos/vCardBrowser/LabelControl.cs b/Source/CSharpDemos/vCardBrowser/LabelControl.cs index 25b6dd1..b46f921 100644 --- a/Source/CSharpDemos/vCardBrowser/LabelControl.cs +++ b/Source/CSharpDemos/vCardBrowser/LabelControl.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : LabelControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/27/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // Compiler: Visual C# // // This is used to edit a vCard's label information. It's nothing elaborate but does let you edit the collection @@ -69,43 +69,43 @@ public override void BindToControls() txtLabelText.DataBindings.Add("Text", this.BindingSource, "Value"); // For the checkboxes, the Format and Parse events are needed to get and set the checked state - Binding b = new Binding("Checked", this.BindingSource, "AddressTypes"); + Binding b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkDomestic.Tag = AddressTypes.Domestic; chkDomestic.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkInternational.Tag = AddressTypes.International; chkInternational.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkPostal.Tag = AddressTypes.Postal; chkPostal.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkParcel.Tag = AddressTypes.Parcel; chkParcel.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkHome.Tag = AddressTypes.Home; chkHome.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkWork.Tag = AddressTypes.Work; chkWork.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "AddressTypes"); + b = new("Checked", this.BindingSource, "AddressTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkPreferred.Tag = AddressTypes.Preferred; @@ -121,11 +121,11 @@ public override void BindToControls() /// /// The sender of the event /// The event arguments - private void CheckBox_Format(object sender, ConvertEventArgs e) + private void CheckBox_Format(object? sender, ConvertEventArgs e) { - CheckBox cb = (CheckBox)((Binding)sender).Control; - AddressTypes checkType = (AddressTypes)cb.Tag; - AddressTypes addrTypes = (AddressTypes)e.Value; + CheckBox cb = (CheckBox)((Binding)sender!).Control; + AddressTypes checkType = (AddressTypes)cb.Tag!; + AddressTypes addrTypes = (AddressTypes)e.Value!; e.Value = (addrTypes & checkType) == checkType; } @@ -135,11 +135,11 @@ private void CheckBox_Format(object sender, ConvertEventArgs e) /// /// The sender of the event /// The event arguments - private void CheckBox_Parse(object sender, ConvertEventArgs e) + private void CheckBox_Parse(object? sender, ConvertEventArgs e) { LabelProperty l = (LabelProperty)this.BindingSource.Current; - CheckBox cb = (CheckBox)((Binding)sender).Control; - AddressTypes checkType = (AddressTypes)cb.Tag; + CheckBox cb = (CheckBox)((Binding)sender!).Control; + AddressTypes checkType = (AddressTypes)cb.Tag!; if(cb.Checked) l.AddressTypes |= checkType; diff --git a/Source/CSharpDemos/vCardBrowser/PhoneControl.cs b/Source/CSharpDemos/vCardBrowser/PhoneControl.cs index 494a722..51330b3 100644 --- a/Source/CSharpDemos/vCardBrowser/PhoneControl.cs +++ b/Source/CSharpDemos/vCardBrowser/PhoneControl.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : PhoneControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/01/2020 -// Note : Copyright 2004-2020, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a vCard's phone information. It's nothing elaborate but does let you edit the collection // fairly well. @@ -85,49 +85,49 @@ public override void BindToControls() // For the checkboxes, the Format and Parse events are needed to get and set the checked state. We // aren't going to check for a few of the less common ones. - Binding b = new Binding("Checked", this.BindingSource, "PhoneTypes"); + Binding b = new("Checked", this.BindingSource, "PhoneTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkWork.Tag = PhoneTypes.Work; chkWork.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "PhoneTypes"); + b = new("Checked", this.BindingSource, "PhoneTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkHome.Tag = PhoneTypes.Home; chkHome.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "PhoneTypes"); + b = new("Checked", this.BindingSource, "PhoneTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkVoice.Tag = PhoneTypes.Voice; chkVoice.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "PhoneTypes"); + b = new("Checked", this.BindingSource, "PhoneTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkFax.Tag = PhoneTypes.Fax; chkFax.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "PhoneTypes"); + b = new("Checked", this.BindingSource, "PhoneTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkMessage.Tag = PhoneTypes.Message; chkMessage.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "PhoneTypes"); + b = new("Checked", this.BindingSource, "PhoneTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkCell.Tag = PhoneTypes.Cell; chkCell.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "PhoneTypes"); + b = new("Checked", this.BindingSource, "PhoneTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkPager.Tag = PhoneTypes.Pager; chkPager.DataBindings.Add(b); - b = new Binding("Checked", this.BindingSource, "PhoneTypes"); + b = new("Checked", this.BindingSource, "PhoneTypes"); b.Format += CheckBox_Format; b.Parse += CheckBox_Parse; chkPreferred.Tag = PhoneTypes.Preferred; @@ -143,11 +143,11 @@ public override void BindToControls() /// /// The sender of the event /// The event arguments - private void CheckBox_Format(object sender, ConvertEventArgs e) + private void CheckBox_Format(object? sender, ConvertEventArgs e) { - CheckBox cb = (CheckBox)((Binding)sender).Control; - PhoneTypes checkType = (PhoneTypes)cb.Tag; - PhoneTypes addrTypes = (PhoneTypes)e.Value; + CheckBox cb = (CheckBox)((Binding)sender!).Control; + PhoneTypes checkType = (PhoneTypes)cb.Tag!; + PhoneTypes addrTypes = (PhoneTypes)e.Value!; e.Value = (addrTypes & checkType) == checkType; } @@ -157,11 +157,11 @@ private void CheckBox_Format(object sender, ConvertEventArgs e) /// /// The sender of the event /// The event arguments - private void CheckBox_Parse(object sender, ConvertEventArgs e) + private void CheckBox_Parse(object? sender, ConvertEventArgs e) { TelephoneProperty t = (TelephoneProperty)this.BindingSource.Current; - CheckBox cb = (CheckBox)((Binding)sender).Control; - PhoneTypes checkType = (PhoneTypes)cb.Tag; + CheckBox cb = (CheckBox)((Binding)sender!).Control; + PhoneTypes checkType = (PhoneTypes)cb.Tag!; if(cb.Checked) t.PhoneTypes |= checkType; diff --git a/Source/CSharpDemos/vCardBrowser/PhotoControl.cs b/Source/CSharpDemos/vCardBrowser/PhotoControl.cs index fe9906d..8727ccf 100644 --- a/Source/CSharpDemos/vCardBrowser/PhotoControl.cs +++ b/Source/CSharpDemos/vCardBrowser/PhotoControl.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : PhotoControl.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a vCard's photo and logo information. It's nothing elaborate but does let you edit the // properties fairly well. @@ -73,12 +73,11 @@ public string ImageFilename var wrq = System.Net.WebRequest.Create(new Uri(value)); - using(var wrsp = wrq.GetResponse()) - using(var s = wrsp.GetResponseStream()) - { - bmImage.Dispose(); - bmImage = new Bitmap(s); - } + using var wrsp = wrq.GetResponse(); + using var s = wrsp.GetResponseStream(); + + bmImage.Dispose(); + bmImage = new Bitmap(s); } catch { @@ -90,17 +89,15 @@ public string ImageFilename { byte[] imageBytes; - using(var c = new System.Net.Http.HttpClient()) - { - imageBytes = c.GetByteArrayAsync(new Uri(value)).Result; - } + using var c = new System.Net.Http.HttpClient(); + + imageBytes = c.GetByteArrayAsync(new Uri(value)).Result; bmImage.Dispose(); - using(var ms = new MemoryStream(imageBytes)) - { - bmImage = new Bitmap(ms); - } + using var ms = new MemoryStream(imageBytes); + + bmImage = new Bitmap(ms); } catch { @@ -136,9 +133,9 @@ public string ImageFilename /// This is used to set or get the image type /// [DefaultValue("GIF"), Description("The image type")] - public string ImageType + public string? ImageType { - get => (string)cboImageType.SelectedItem; + get => (string)cboImageType.SelectedItem!; set { int idx = (value != null) ? cboImageType.Items.IndexOf(value) : 0; @@ -160,9 +157,9 @@ public bool IsInline get => chkInline.Checked; set => chkInline.Checked = value; } -#endregion + #endregion -#region Constructor + #region Constructor //===================================================================== /// @@ -174,9 +171,9 @@ public PhotoControl() bmImage = new Bitmap(1, 1); } -#endregion + #endregion -#region Helper methods + #region Helper methods //===================================================================== /// @@ -212,15 +209,14 @@ public void SetImageBytes(byte[] imageBytes) /// The bytes for the current image public byte[] GetImageBytes() { - using(var ms = new MemoryStream()) - { - bmImage.Save(ms, bmImage.RawFormat); - return ms.ToArray(); - } + using var ms = new MemoryStream(); + + bmImage.Save(ms, bmImage.RawFormat); + return ms.ToArray(); } -#endregion + #endregion -#region Event handlers + #region Event handlers //===================================================================== /// @@ -245,34 +241,33 @@ private void btnLoad_Click(object sender, EventArgs e) { string extension; - using(OpenFileDialog dlg = new OpenFileDialog()) + using var dlg = new OpenFileDialog(); + + dlg.Title = "Load Image File"; + dlg.DefaultExt = "jpg"; + dlg.Filter = "Image files|*.jpg;*.gif;*.tif;*.bmp"; + dlg.InitialDirectory = Environment.CurrentDirectory; + + if(dlg.ShowDialog() == DialogResult.OK) { - dlg.Title = "Load Image File"; - dlg.DefaultExt = "jpg"; - dlg.Filter = "Image files|*.jpg;*.gif;*.tif;*.bmp"; - dlg.InitialDirectory = Environment.CurrentDirectory; + this.ImageFilename = dlg.FileName; - if(dlg.ShowDialog() == DialogResult.OK) + // If it loaded successfully, default to storing it inline + if(bmImage.Height != 1 && bmImage.Width != 1) { - this.ImageFilename = dlg.FileName; - - // If it loaded successfully, default to storing it inline - if(bmImage.Height != 1 && bmImage.Width != 1) - { - this.IsInline = true; - extension = Path.GetExtension(dlg.FileName).ToUpperInvariant(); + this.IsInline = true; + extension = Path.GetExtension(dlg.FileName).ToUpperInvariant(); - if(extension.Length > 1 && extension[0] == '.') - extension = extension.Substring(1); + if(extension.Length > 1 && extension[0] == '.') + extension = extension.Substring(1); - if(extension == "JPG") - extension = "JPEG"; + if(extension == "JPG") + extension = "JPEG"; - this.ImageType = extension; - } + this.ImageType = extension; } } } -#endregion + #endregion } } diff --git a/Source/CSharpDemos/vCardBrowser/VCardBrowserForm.Designer.cs b/Source/CSharpDemos/vCardBrowser/VCardBrowserForm.Designer.cs index 5c62d15..e5bf95c 100644 --- a/Source/CSharpDemos/vCardBrowser/VCardBrowserForm.Designer.cs +++ b/Source/CSharpDemos/vCardBrowser/VCardBrowserForm.Designer.cs @@ -15,11 +15,8 @@ protected override void Dispose(bool disposing) { if(disposing) { - if(sf != null) - sf.Dispose(); - - if(components != null) - components.Dispose(); + sf?.Dispose(); + components?.Dispose(); } base.Dispose(disposing); } diff --git a/Source/CSharpDemos/vCardBrowser/VCardBrowserForm.cs b/Source/CSharpDemos/vCardBrowser/VCardBrowserForm.cs index 1871ad5..dac6388 100644 --- a/Source/CSharpDemos/vCardBrowser/VCardBrowserForm.cs +++ b/Source/CSharpDemos/vCardBrowser/VCardBrowserForm.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : VCardBrowserForm.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2020 -// Note : Copyright 2004-2020, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is a simple demonstration application that shows how to load, save, and manage a set of vCards including // how to edit the various vCard properties. @@ -45,7 +45,7 @@ public partial class VCardBrowserForm : System.Windows.Forms.Form private VCardCollection vCards; private bool wasModified; - private StringFormat sf; + private readonly StringFormat sf; #endregion @@ -88,7 +88,7 @@ public VCardBrowserForm() CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern; cboVersion.SelectedIndex = 0; - vCards = new VCardCollection(); + vCards = []; LoadGridWithVCards(); } #endregion @@ -113,7 +113,7 @@ private void LoadGridWithVCards() // the collection can be sorted in the grid by clicking on the column headers. vCards.Sort((x, y) => { - string sortName1, sortName2; + string? sortName1, sortName2; // Get the names to compare. Precedence is given to the SortString property or SortAs parameter // as that is the purpose of their existence. @@ -161,7 +161,7 @@ private void LoadGridWithVCards() /// /// The sender of the event /// The event arguments - private void vCards_ListChanged(object sender, ListChangedEventArgs e) + private void vCards_ListChanged(object? sender, ListChangedEventArgs e) { miClear.Enabled = btnEdit.Enabled = btnDelete.Enabled = cboVersion.Enabled = btnApplyVersion.Enabled = (vCards.Count != 0); @@ -194,47 +194,46 @@ private void miOpen_Click(object sender, EventArgs e) MessageBoxDefaultButton.Button2) == DialogResult.No) return; - using(OpenFileDialog dlg = new OpenFileDialog()) - { - dlg.Title = "Load vCard File"; - dlg.DefaultExt = "vcf"; - dlg.Filter = "VCF files (*.vcf)|*.vcf|All files (*.*)|*.*"; - dlg.InitialDirectory = Path.GetFullPath(Path.Combine( - Environment.CurrentDirectory, @"..\..\..\..\..\PDIFiles")); + using var dlg = new OpenFileDialog(); + + dlg.Title = "Load vCard File"; + dlg.DefaultExt = "vcf"; + dlg.Filter = "VCF files (*.vcf)|*.vcf|All files (*.*)|*.*"; + dlg.InitialDirectory = Path.GetFullPath(Path.Combine( + Environment.CurrentDirectory, @"..\..\..\..\..\PDIFiles")); - if(dlg.ShowDialog() == DialogResult.OK) + if(dlg.ShowDialog() == DialogResult.OK) + { + try { - try - { - this.Cursor = Cursors.WaitCursor; + this.Cursor = Cursors.WaitCursor; - // Parse the vCard information from the file and load the data grid with some basic - // information about the vCards in it. - vCards = VCardParser.ParseFromFile(dlg.FileName); - this.LoadGridWithVCards(); + // Parse the vCard information from the file and load the data grid with some basic + // information about the vCards in it. + vCards = VCardParser.ParseFromFile(dlg.FileName); + this.LoadGridWithVCards(); - lblFilename.Text = dlg.FileName; - } - catch(Exception ex) - { - string error = $"Unable to load vCards:\n{ex.Message}"; + lblFilename.Text = dlg.FileName; + } + catch(Exception ex) + { + string error = $"Unable to load vCards:\n{ex.Message}"; - if(ex.InnerException != null) - { - error += ex.InnerException.Message + "\n"; + if(ex.InnerException != null) + { + error += ex.InnerException.Message + "\n"; - if(ex.InnerException.InnerException != null) - error += ex.InnerException.InnerException.Message; - } + if(ex.InnerException.InnerException != null) + error += ex.InnerException.InnerException.Message; + } - System.Diagnostics.Debug.Write(ex); + System.Diagnostics.Debug.Write(ex); - MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - finally - { - this.Cursor = Cursors.Default; - } + MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + this.Cursor = Cursors.Default; } } } @@ -246,58 +245,57 @@ private void miOpen_Click(object sender, EventArgs e) /// The event arguments private void miSave_Click(object sender, EventArgs e) { - using(SaveFileDialog dlg = new SaveFileDialog()) + using var dlg = new SaveFileDialog(); + + dlg.Title = "Save vCard File"; + dlg.DefaultExt = "vcf"; + dlg.Filter = "VCF files (*.vcf)|*.vcf|All files (*.*)|*.*"; + dlg.InitialDirectory = Path.GetFullPath(Path.Combine( + Environment.CurrentDirectory, @"..\..\..\..\..\PDIFiles")); + dlg.FileName = lblFilename.Text; + + if(dlg.ShowDialog() == DialogResult.OK) { - dlg.Title = "Save vCard File"; - dlg.DefaultExt = "vcf"; - dlg.Filter = "VCF files (*.vcf)|*.vcf|All files (*.*)|*.*"; - dlg.InitialDirectory = Path.GetFullPath(Path.Combine( - Environment.CurrentDirectory, @"..\..\..\..\..\PDIFiles")); - dlg.FileName = lblFilename.Text; - - if(dlg.ShowDialog() == DialogResult.OK) + try { - try + this.Cursor = Cursors.WaitCursor; + + // Enforce UTF-8 encoding if using vCard 4.0 + if((!miFileUnicode.Checked || !miPropUnicode.Checked) && vCards.Any( + c => c.Version == SpecificationVersions.vCard40)) { - this.Cursor = Cursors.WaitCursor; - - // Enforce UTF-8 encoding if using vCard 4.0 - if((!miFileUnicode.Checked || !miPropUnicode.Checked) && vCards.Any( - c => c.Version == SpecificationVersions.vCard40)) - { - this.ChangeFileEncoding_Click(miFileUnicode, e); - } - - // Open the file and write the vCards to it. We'll use the same encoding method used by - // the parser. - using(var sw = new StreamWriter(dlg.FileName, false, PDIParser.DefaultEncoding)) - { - vCards.WriteToStream(sw); - } - - lblFilename.Text = dlg.FileName; - wasModified = false; + this.ChangeFileEncoding_Click(miFileUnicode, e); } - catch(Exception ex) - { - string error = $"Unable to save vCards:\n{ex.Message}"; - - if(ex.InnerException != null) - { - error += ex.InnerException.Message + "\n"; - if(ex.InnerException.InnerException != null) - error += ex.InnerException.InnerException.Message; - } + // Open the file and write the vCards to it. We'll use the same encoding method used by + // the parser. + using(var sw = new StreamWriter(dlg.FileName, false, PDIParser.DefaultEncoding)) + { + vCards.WriteToStream(sw); + } - System.Diagnostics.Debug.Write(ex); + lblFilename.Text = dlg.FileName; + wasModified = false; + } + catch(Exception ex) + { + string error = $"Unable to save vCards:\n{ex.Message}"; - MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - finally + if(ex.InnerException != null) { - this.Cursor = Cursors.Default; + error += ex.InnerException.Message + "\n"; + + if(ex.InnerException.InnerException != null) + error += ex.InnerException.InnerException.Message; } + + System.Diagnostics.Debug.Write(ex); + + MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + this.Cursor = Cursors.Default; } } } @@ -321,10 +319,9 @@ private void miClear_Click(object sender, EventArgs e) /// The event arguments private void miAbout_Click(object sender, EventArgs e) { - using(AboutDlg dlg = new AboutDlg()) - { - dlg.ShowDialog(); - } + using var dlg = new AboutDlg(); + + dlg.ShowDialog(); } /// @@ -344,18 +341,17 @@ private void miExit_Click(object sender, EventArgs e) /// The event arguments private void btnAdd_Click(object sender, EventArgs e) { - using(VCardPropertiesDlg dlg = new VCardPropertiesDlg()) + using var dlg = new VCardPropertiesDlg(); + + if(dlg.ShowDialog() == DialogResult.OK) { - if(dlg.ShowDialog() == DialogResult.OK) - { - VCard newVCard = new VCard(); - dlg.GetValues(newVCard); + var newVCard = new VCard(); + dlg.GetValues(newVCard); - // Create a unique ID for the new vCard - newVCard.UniqueId.AssignNewId(true); + // Create a unique ID for the new vCard + newVCard.UniqueId.AssignNewId(true); - vCards.Add(newVCard); - } + vCards.Add(newVCard); } } @@ -373,17 +369,16 @@ private void btnEdit_Click(object sender, EventArgs e) return; } - using(VCardPropertiesDlg dlg = new VCardPropertiesDlg()) - { - this.Cursor = Cursors.WaitCursor; - dlg.SetValues(vCards[dgvCards.CurrentCellAddress.Y]); - this.Cursor = Cursors.Default; + using var dlg = new VCardPropertiesDlg(); + + this.Cursor = Cursors.WaitCursor; + dlg.SetValues(vCards[dgvCards.CurrentCellAddress.Y]); + this.Cursor = Cursors.Default; - if(dlg.ShowDialog() == DialogResult.OK) - { - dlg.GetValues(vCards[dgvCards.CurrentCellAddress.Y]); - wasModified = true; - } + if(dlg.ShowDialog() == DialogResult.OK) + { + dlg.GetValues(vCards[dgvCards.CurrentCellAddress.Y]); + wasModified = true; } } @@ -512,7 +507,7 @@ private void dgvCards_CellPainting(object sender, DataGridViewCellPaintingEventA if(e.RowIndex > -1 && e.ColumnIndex == 0) { - var specVer = (SpecificationVersions)e.Value; + var specVer = (SpecificationVersions)e.Value!; string version = (specVer == SpecificationVersions.vCard21) ? "2.1" : (specVer == SpecificationVersions.vCard30) ? "3.0" : "4.0"; @@ -520,14 +515,13 @@ private void dgvCards_CellPainting(object sender, DataGridViewCellPaintingEventA // Based the foreground color on the selected state if((e.State & DataGridViewElementStates.Selected) != 0) - foreColor = e.CellStyle.SelectionForeColor; + foreColor = e.CellStyle!.SelectionForeColor; else - foreColor = e.CellStyle.ForeColor; + foreColor = e.CellStyle!.ForeColor; - using(SolidBrush b = new SolidBrush(foreColor)) - { - e.Graphics.DrawString(version, e.CellStyle.Font, b, e.CellBounds, sf); - } + using var b = new SolidBrush(foreColor); + + e.Graphics!.DrawString(version, e.CellStyle.Font, b, e.CellBounds, sf); e.Handled = true; } diff --git a/Source/CSharpDemos/vCardBrowser/VCardPropertiesDlg.cs b/Source/CSharpDemos/vCardBrowser/VCardPropertiesDlg.cs index df49029..4d27587 100644 --- a/Source/CSharpDemos/vCardBrowser/VCardPropertiesDlg.cs +++ b/Source/CSharpDemos/vCardBrowser/VCardPropertiesDlg.cs @@ -2,8 +2,8 @@ // System : EWSoftware PDI Demonstration Applications // File : VCardPropertiesDlg.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +// Updated : 01/05/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is used to edit a vCard's properties. It supports most of the common properties of the vCard including // photo, logo, and sound. @@ -56,12 +56,12 @@ public VCardPropertiesDlg() cboSex.DisplayMember = "Display"; cboSex.DataSource = new List { - new ListItem('\0', String.Empty), - new ListItem('M', "Male"), - new ListItem('F', "Female"), - new ListItem('O', "Other"), - new ListItem('N', "N/A"), - new ListItem('U', "Unknown") + new('\0', String.Empty), + new('M', "Male"), + new('F', "Female"), + new('O', "Other"), + new('N', "N/A"), + new('U', "Unknown") }; } #endregion @@ -131,7 +131,12 @@ private void btnWebPage_Click(object sender, EventArgs e) { try { - System.Diagnostics.Process.Start(txtWebPage.Text); + System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo + { + FileName = txtWebPage.Text, + UseShellExecute = true, + }); + } catch(Exception ex) { @@ -308,7 +313,7 @@ public void GetValues(VCard vCard) // We'll parse nicknames as a comma separated string vCard.Nickname.NicknamesString = txtNickname.Text; - vCard.Gender.Sex = (cboSex.SelectedIndex == 0) ? (char?)null : (char)cboSex.SelectedValue; + vCard.Gender.Sex = (cboSex.SelectedIndex == 0) ? null : (char)cboSex.SelectedValue!; vCard.Gender.GenderIdentity = txtGenderIdentity.Text; // For the collections, we'll clear the existing items and copy the modified items from the browse diff --git a/Source/CSharpDemos/vCardBrowser/app.config b/Source/CSharpDemos/vCardBrowser/app.config index 75f0734..e1665fe 100644 --- a/Source/CSharpDemos/vCardBrowser/app.config +++ b/Source/CSharpDemos/vCardBrowser/app.config @@ -1,8 +1,5 @@ - - - diff --git a/Source/CSharpDemos/vCardBrowser/app.manifest b/Source/CSharpDemos/vCardBrowser/app.manifest deleted file mode 100644 index 5dbcd41..0000000 --- a/Source/CSharpDemos/vCardBrowser/app.manifest +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Source/CSharpDemos/vCardBrowser/vCardBrowser.csproj b/Source/CSharpDemos/vCardBrowser/vCardBrowser.csproj index 9b224fa..54344d9 100644 --- a/Source/CSharpDemos/vCardBrowser/vCardBrowser.csproj +++ b/Source/CSharpDemos/vCardBrowser/vCardBrowser.csproj @@ -1,30 +1,32 @@  - - WinExe - net6.0-windows;net40 - true - False - False - False - False - False - False - ProductAttribute - vCardBrowser.snk - true - true - AllEnabledByDefault - - - - - - - - - + + WinExe + net8.0-windows;net40 + true + False + False + False + False + False + False + ProductAttribute + vCardBrowser.snk + true + true + AllEnabledByDefault + latest + enable + + + + + + + + + - - - + + + \ No newline at end of file diff --git a/Source/EWSPDI/DailyFrequency.cs b/Source/EWSPDI/DailyFrequency.cs index 3a8fafb..f050d26 100644 --- a/Source/EWSPDI/DailyFrequency.cs +++ b/Source/EWSPDI/DailyFrequency.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : DailyFrequency.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/22/2014 -// Note : Copyright 2003-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a class used to implements the Daily frequency rules // @@ -36,10 +35,10 @@ internal sealed class DailyFrequency : IFrequencyRules /// The start date of the range limiting the instances generated /// The end date of the range limiting the instances generated /// The first instance date or null if there are no more instances - public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, + public RecurDateTime? FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, RecurDateTime to) { - RecurDateTime rdt = new RecurDateTime(start); + RecurDateTime rdt = new(start); int adjust; // Get the difference between the recurrence start and the limiting range start @@ -56,7 +55,9 @@ public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime if(RecurDateTime.Compare(rdt, end, RecurDateTime.DateTimePart.Day) > 0 || RecurDateTime.Compare(rdt, to, RecurDateTime.DateTimePart.Day) > 0) + { return null; + } return rdt; } @@ -76,7 +77,9 @@ public bool FindNext(Recurrence r, RecurDateTime end, RecurDateTime to, RecurDat if(RecurDateTime.Compare(last, end, RecurDateTime.DateTimePart.Day) > 0 || RecurDateTime.Compare(last, to, RecurDateTime.DateTimePart.Day) > 0) + { return false; + } return true; } diff --git a/Source/EWSPDI/DateUtils.cs b/Source/EWSPDI/DateUtils.cs index 79b2ccb..0b370e1 100644 --- a/Source/EWSPDI/DateUtils.cs +++ b/Source/EWSPDI/DateUtils.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : DateUtils.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2003-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a sealed class that contains various helpful date utility methods used by other classes in // the PDI library. @@ -35,13 +34,13 @@ public static class DateUtils //===================================================================== // These are used to parse date/time strings in ISO 8601 format - private static Regex reISO8601 = new Regex(@"^\s*(?\d{4})-?" + + private static readonly Regex reISO8601 = new(@"^\s*(?\d{4})-?" + @"(?\d{2})-?(?\d{2})(? - public static long TicksPerMonth => (long)(TimeSpan.TicksPerDay * Duration.DaysInOneMonth); + public static long TicksPerMonth => (long)(TimeSpan.TicksPerDay * DaysInOneMonth); /// /// This returns the number of timer ticks in one year based on the current setting of /// . /// - public static long TicksPerYear => (long)(TimeSpan.TicksPerDay * Duration.DaysInOneYear); + public static long TicksPerYear => (long)(TimeSpan.TicksPerDay * DaysInOneYear); /// /// This allows access to the underlying object @@ -163,22 +163,22 @@ public long Ticks /// /// Note that this returns the number of whole days in the duration rather than /// the number of whole days in the underlying time span. - public int Days => (int)(ts.TotalDays % Duration.DaysInOneYear % Duration.DaysInOneMonth % 7); + public int Days => (int)(ts.TotalDays % DaysInOneYear % DaysInOneMonth % 7); /// /// Gets the number of whole weeks represented by this instance /// - public int Weeks => (int)(ts.TotalDays % Duration.DaysInOneYear % Duration.DaysInOneMonth / 7); + public int Weeks => (int)(ts.TotalDays % DaysInOneYear % DaysInOneMonth / 7); /// /// Gets the number of whole months represented by this instance /// - public int Months => (int)(ts.TotalDays % Duration.DaysInOneYear / Duration.DaysInOneMonth); + public int Months => (int)(ts.TotalDays % DaysInOneYear / DaysInOneMonth); /// /// Gets the number of whole years represented by this instance /// - public int Years => (int)(ts.TotalDays / Duration.DaysInOneYear); + public int Years => (int)(ts.TotalDays / DaysInOneYear); /// /// Gets the value of this instance expressed in whole and fractional weeks @@ -188,12 +188,12 @@ public long Ticks /// /// Gets the value of this instance expressed in whole and fractional months /// - public double TotalMonths => ts.TotalDays / Duration.DaysInOneMonth; + public double TotalMonths => ts.TotalDays / DaysInOneMonth; /// /// Gets the value of this instance expressed in whole and fractional years /// - public double TotalYears => ts.TotalDays / Duration.DaysInOneYear; + public double TotalYears => ts.TotalDays / DaysInOneYear; #endregion @@ -226,7 +226,7 @@ public Duration(TimeSpan timeSpan) /// The time span used to initialize the instance public Duration(int weeks, TimeSpan timeSpan) { - ts = timeSpan.Add(new TimeSpan(weeks * Duration.TicksPerWeek)); + ts = timeSpan.Add(new TimeSpan(weeks * TicksPerWeek)); } /// @@ -237,8 +237,8 @@ public Duration(int weeks, TimeSpan timeSpan) /// The time span used to initialize the instance public Duration(int months, int weeks, TimeSpan timeSpan) { - ts = timeSpan.Add(new TimeSpan(months * Duration.TicksPerMonth)).Add( - new TimeSpan(weeks * Duration.TicksPerWeek)); + ts = timeSpan.Add(new TimeSpan(months * TicksPerMonth)).Add( + new TimeSpan(weeks * TicksPerWeek)); } /// @@ -250,9 +250,9 @@ public Duration(int months, int weeks, TimeSpan timeSpan) /// The time span used to initialize the instance public Duration(int years, int months, int weeks, TimeSpan timeSpan) { - ts = timeSpan.Add(new TimeSpan(years * Duration.TicksPerYear)).Add( - new TimeSpan(months * Duration.TicksPerMonth)).Add( - new TimeSpan(weeks * Duration.TicksPerWeek)); + ts = timeSpan.Add(new TimeSpan(years * TicksPerYear)).Add( + new TimeSpan(months * TicksPerMonth)).Add( + new TimeSpan(weeks * TicksPerWeek)); } /// @@ -264,11 +264,11 @@ public Duration(int years, int months, int weeks, TimeSpan timeSpan) /// minutes, and seconds. Any of the parts except the leading 'P' and the 'T' time separator can be /// omitted entirely if not needed. /// This is thrown if the specified duration string is not valid - public Duration(string duration) + public Duration(string? duration) { int years = 0, months = 0, weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0; - // If null or empty, default to zero + // If null or whitespace, default to zero if(String.IsNullOrWhiteSpace(duration)) { ts = TimeSpan.Zero; @@ -304,13 +304,13 @@ public Duration(string duration) ts = new TimeSpan(days, hours, minutes, seconds, 0); if(years != 0) - ts += new TimeSpan(years * Duration.TicksPerYear); + ts += new TimeSpan(years * TicksPerYear); if(months != 0) - ts += new TimeSpan(months * Duration.TicksPerMonth); + ts += new TimeSpan(months * TicksPerMonth); if(weeks != 0) - ts += new TimeSpan(weeks * Duration.TicksPerWeek); + ts += new TimeSpan(weeks * TicksPerWeek); if(m.Groups["Negative"].Value == "-") ts = ts.Negate(); @@ -339,7 +339,7 @@ public static Duration FromWeeks(double value) /// A that represents the value public static Duration FromMonths(double value) { - return new Duration(TimeSpan.FromDays(value * Duration.DaysInOneMonth)); + return new Duration(TimeSpan.FromDays(value * DaysInOneMonth)); } /// @@ -350,7 +350,7 @@ public static Duration FromMonths(double value) /// A that represents the value public static Duration FromYears(double value) { - return new Duration(TimeSpan.FromDays(value * Duration.DaysInOneYear)); + return new Duration(TimeSpan.FromDays(value * DaysInOneYear)); } /// @@ -362,11 +362,11 @@ public static Duration FromYears(double value) /// specified by s, or if the conversion failed. This parameter is passed in /// uninitialized. /// True if successfully parsed or false if the value could not be parsed - public static bool TryParse(string duration, out Duration result) + public static bool TryParse(string? duration, out Duration result) { - if(!reDuration.IsMatch(duration)) + if(String.IsNullOrWhiteSpace(duration) || !reDuration.IsMatch(duration)) { - result = Duration.Zero; + result = Zero; return false; } @@ -376,7 +376,7 @@ public static bool TryParse(string duration, out Duration result) } catch(OverflowException ) { - result = Duration.Zero; + result = Zero; return false; } @@ -405,7 +405,7 @@ public static bool Equals(Duration d1, Duration d2) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - return (obj != null && (obj is Duration) && ts.Ticks == ((Duration)obj).Ticks); + return obj is Duration d && ts.Ticks == d.Ticks; } /// @@ -434,7 +434,7 @@ public override int GetHashCode() /// There are two overloads for this method public override string ToString() { - return this.ToString(Duration.MaxUnit.Years); + return this.ToString(MaxUnit.Years); } /// @@ -449,8 +449,8 @@ public override string ToString() /// time unit of weeks if a month is defined as 30 days). public string ToString(MaxUnit maxUnit) { - StringBuilder sb = new StringBuilder("P", 50); - Duration d = new Duration(this.Ticks); + StringBuilder sb = new("P", 50); + Duration d = new(this.Ticks); int years, months, weeks, days, hours, minutes, seconds; @@ -461,9 +461,9 @@ public string ToString(MaxUnit maxUnit) { case MaxUnit.Months: years = 0; - months = (int)(d.TimeSpan.Days / Duration.DaysInOneMonth); - weeks = d.TimeSpan.Days - (int)(months * Duration.DaysInOneMonth); - days = d.TimeSpan.Days - (int)(months * Duration.DaysInOneMonth) - (int)(weeks * 7); + months = (int)(d.TimeSpan.Days / DaysInOneMonth); + weeks = d.TimeSpan.Days - (int)(months * DaysInOneMonth); + days = d.TimeSpan.Days - (int)(months * DaysInOneMonth) - (int)(weeks * 7); hours = d.TimeSpan.Hours; minutes = d.TimeSpan.Minutes; seconds = d.TimeSpan.Seconds; @@ -563,7 +563,7 @@ public string ToString(MaxUnit maxUnit) /// There are two overloads for this method public string ToDescription() { - return this.ToDescription(Duration.MaxUnit.Years); + return this.ToDescription(MaxUnit.Years); } /// @@ -578,8 +578,8 @@ public string ToDescription() /// maximum time unit of weeks if a month is defined as 30 days). public string ToDescription(MaxUnit maxUnit) { - StringBuilder sb = new StringBuilder(50); - Duration d = new Duration(this.Ticks); + StringBuilder sb = new (50); + Duration d = new(this.Ticks); int years, months, weeks, days, hours, minutes, seconds; @@ -590,9 +590,9 @@ public string ToDescription(MaxUnit maxUnit) { case MaxUnit.Months: years = 0; - months = (int)(d.TimeSpan.Days / Duration.DaysInOneMonth); - weeks = d.TimeSpan.Days - (int)(months * Duration.DaysInOneMonth); - days = d.TimeSpan.Days - (int)(months * Duration.DaysInOneMonth) - (int)(weeks * 7); + months = (int)(d.TimeSpan.Days / DaysInOneMonth); + weeks = d.TimeSpan.Days - (int)(months * DaysInOneMonth); + days = d.TimeSpan.Days - (int)(months * DaysInOneMonth) - (int)(weeks * 7); hours = d.TimeSpan.Hours; minutes = d.TimeSpan.Minutes; seconds = d.TimeSpan.Seconds; @@ -724,10 +724,10 @@ public string ToDescription(MaxUnit maxUnit) /// This is thrown if the object to be compared is not a Duration public int CompareTo(object obj) { - if(!(obj is Duration)) + if(obj is not Duration) throw new ArgumentException(LR.GetString("ExDurBadCompareObject")); - return Duration.Compare(this, (Duration)obj); + return Compare(this, (Duration)obj); } /// @@ -756,7 +756,7 @@ public static int Compare(Duration d1, Duration d2) /// True if equal, false if not public static bool operator == (Duration d1, Duration d2) { - return (Duration.Compare(d1, d2) == 0); + return Compare(d1, d2) == 0; } /// @@ -767,7 +767,7 @@ public static int Compare(Duration d1, Duration d2) /// True if not equal, false if they are equal public static bool operator != (Duration d1, Duration d2) { - return (Duration.Compare(d1, d2) != 0); + return Compare(d1, d2) != 0; } /// @@ -778,7 +778,7 @@ public static int Compare(Duration d1, Duration d2) /// True if r1 is less than r2, false if not public static bool operator < (Duration d1, Duration d2) { - return (Duration.Compare(d1, d2) < 0); + return Compare(d1, d2) < 0; } /// @@ -789,7 +789,7 @@ public static int Compare(Duration d1, Duration d2) /// True if r1 is greater than r2, false if not public static bool operator > (Duration d1, Duration d2) { - return (Duration.Compare(d1, d2) > 0); + return Compare(d1, d2) > 0; } /// @@ -800,7 +800,7 @@ public static int Compare(Duration d1, Duration d2) /// True if r1 is less than or equal r2, false if not public static bool operator <= (Duration d1, Duration d2) { - return (Duration.Compare(d1, d2) <= 0); + return Compare(d1, d2) <= 0; } /// @@ -811,7 +811,7 @@ public static int Compare(Duration d1, Duration d2) /// True if r1 is greater than or equal r2, false if not public static bool operator >= (Duration d1, Duration d2) { - return (Duration.Compare(d1, d2) >= 0); + return Compare(d1, d2) >= 0; } #endregion } diff --git a/Source/EWSPDI/EWSoftware.PDI.csproj b/Source/EWSPDI/EWSoftware.PDI.csproj index d8fac04..6933afa 100644 --- a/Source/EWSPDI/EWSoftware.PDI.csproj +++ b/Source/EWSPDI/EWSoftware.PDI.csproj @@ -7,10 +7,10 @@ Eric Woodruff EWSoftware Personal Data Interchange Library EWSoftware PDI Library - Copyright (c) 2003-2023, Eric Woodruff, All Rights Reserved + Copyright (c) 2003-2025, Eric Woodruff, All Rights Reserved en - 2023.1.2.0 - 23.1.2.0 + 2025.1.9.0 + 25.1.9.0 This library contains the core set of useful Personal Data Interchange (PDI) and date utility classes for .NET applications. They can be used for calculating holiday dates, recurrences, etc. See the project website for the code, a help file, and demos. Eric Woodruff https://raw.githubusercontent.com/EWSoftware/PDI/master/EWSPDI.png @@ -21,34 +21,28 @@ https://github.com/EWSoftware/PDI MS-PL Targets .NET Framework 4.0 and later and .NET Standard 2.0 and later - true + ReadMe.md False False False False + true ..\EWSPDI.snk true AllEnabledByDefault pdbonly true + latest + enable - - - - - - - true - \ - + + - - diff --git a/Source/EWSPDI/FixedHoliday.cs b/Source/EWSPDI/FixedHoliday.cs index a4fbcf4..3fd141d 100644 --- a/Source/EWSPDI/FixedHoliday.cs +++ b/Source/EWSPDI/FixedHoliday.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : FixedHolidays.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2021 -// Note : Copyright 2003-2021, Eric Woodruff, All rights reserved +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a class used to automatically calculate fixed holidays. The class is serializable. // @@ -212,11 +212,11 @@ public override DateTime ToDateTime(int year) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is FixedHoliday h)) + if(obj is not FixedHoliday h) return false; - return (this == h || (this.Month == h.Month && dayOfMonth == h.Day && - adjustFixed == h.AdjustFixedDate && this.Description == h.Description)); + return this == h || (this.Month == h.Month && dayOfMonth == h.Day && + adjustFixed == h.AdjustFixedDate && this.Description == h.Description); } /// diff --git a/Source/EWSPDI/FloatingHoliday.cs b/Source/EWSPDI/FloatingHoliday.cs index e176166..692e7ce 100644 --- a/Source/EWSPDI/FloatingHoliday.cs +++ b/Source/EWSPDI/FloatingHoliday.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : FloatingHolidays.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2021 -// Note : Copyright 2003-2021, Eric Woodruff, All rights reserved +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a class used to automatically calculate floating holidays. The class is serializable. // @@ -211,12 +211,12 @@ public override DateTime ToDateTime(int year) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is FloatingHoliday h)) + if(obj is not FloatingHoliday h) return false; - return (this == h || (this.Month == h.Month && dayOfWeek == h.Weekday && + return this == h || (this.Month == h.Month && dayOfWeek == h.Weekday && holidayOccurrence == h.Occurrence && holidayOffset == h.Offset && - this.Description == h.Description)); + this.Description == h.Description); } /// diff --git a/Source/EWSPDI/Holiday.cs b/Source/EWSPDI/Holiday.cs index b3d8f3a..343ad81 100644 --- a/Source/EWSPDI/Holiday.cs +++ b/Source/EWSPDI/Holiday.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : Holidays.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2021 -// Note : Copyright 2003-2021, Eric Woodruff, All rights reserved +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains an abstract base classes used to automatically calculate holiday dates // @@ -41,7 +41,7 @@ public abstract class Holiday : ICloneable /// /// This sets or gets the month used for the holiday /// - /// An exception will be thrown if the month is not + /// An exception will be thrown if the month is not /// between 1 and 12. /// [XmlAttribute] @@ -61,7 +61,7 @@ public virtual int Month /// This sets or gets a description for the holiday /// [XmlText] - public string Description { get; set; } + public string Description { get; set; } = null!; /// /// The minimum year for the holiday diff --git a/Source/EWSPDI/HourlyFrequency.cs b/Source/EWSPDI/HourlyFrequency.cs index d660bd3..fb71093 100644 --- a/Source/EWSPDI/HourlyFrequency.cs +++ b/Source/EWSPDI/HourlyFrequency.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : HourlyFrequency.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/22/2014 -// Note : Copyright 2003-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a class used to implements the Hourly frequency rules // @@ -36,10 +35,10 @@ internal sealed class HourlyFrequency : IFrequencyRules /// The start date of the range limiting the instances generated /// The end date of the range limiting the instances generated /// The first instance date or null if there are no more instances - public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, + public RecurDateTime? FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, RecurDateTime to) { - RecurDateTime rdt = new RecurDateTime(start); + RecurDateTime rdt = new(start); int adjust; if(RecurDateTime.Compare(start, from, @@ -58,7 +57,9 @@ public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime if(RecurDateTime.Compare(rdt, end, RecurDateTime.DateTimePart.Hour) > 0 || RecurDateTime.Compare(rdt, to, RecurDateTime.DateTimePart.Hour) > 0) + { return null; + } return rdt; } @@ -78,7 +79,9 @@ public bool FindNext(Recurrence r, RecurDateTime end, RecurDateTime to, RecurDat if(RecurDateTime.Compare(last, end, RecurDateTime.DateTimePart.Hour) > 0 || RecurDateTime.Compare(last, to, RecurDateTime.DateTimePart.Hour) > 0) + { return false; + } return true; } diff --git a/Source/EWSPDI/IFrequencyRules.cs b/Source/EWSPDI/IFrequencyRules.cs index 6dd415c..e278e55 100644 --- a/Source/EWSPDI/IFrequencyRules.cs +++ b/Source/EWSPDI/IFrequencyRules.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : IFrequencyRules.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/22/2014 -// Note : Copyright 2003-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains an interface that defines the methods used to expand or filter recurrence instances based // on the various rules in a recurrence @@ -42,7 +41,7 @@ internal interface IFrequencyRules /// The start date of the range limiting the instances generated /// The end date of the range limiting the instances generated /// The first instance date or null if there are no more instances in the given ranges - RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, + RecurDateTime? FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, RecurDateTime to); /// diff --git a/Source/EWSPDI/ListItem.cs b/Source/EWSPDI/ListItem.cs index bfcba1c..312efc1 100644 --- a/Source/EWSPDI/ListItem.cs +++ b/Source/EWSPDI/ListItem.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ListItem.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/22/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a simple list item object that can be used to obtain a list of values suitable for binding // to a combo box, list box, etc. The Windows Forms user controls use this to bind the values and descriptions @@ -41,7 +40,7 @@ public class ListItem /// /// Specify this property name for the ValueMember or DataValueField property of /// the control using the item as part of its data source. - public object Value { get; set; } + public object? Value { get; set; } /// /// This returns the display text for the item @@ -69,7 +68,7 @@ public ListItem() : this(null, null) /// /// The value for the item /// The display text will be set to the string representation of the value - public ListItem(object value) : this(value, null) + public ListItem(object? value) : this(value, null) { } @@ -102,14 +101,14 @@ public ListItem(object value) : this(value, null) /// cboSortOrder.SelectedIndex = 0 /// /// - public ListItem(object value, string text) + public ListItem(object? value, string? text) { this.Value = value; if(String.IsNullOrEmpty(text)) this.Display = (value != null) ? value.ToString() : String.Empty; else - this.Display = text; + this.Display = text!; } #endregion diff --git a/Source/EWSPDI/LocalizedResources.cs b/Source/EWSPDI/LocalizedResources.cs index b223d20..7ebed9f 100644 --- a/Source/EWSPDI/LocalizedResources.cs +++ b/Source/EWSPDI/LocalizedResources.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : LocalizedResources.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains some internal classes used to manage the localized resources for the assembly // @@ -38,10 +37,10 @@ internal static class LR private const string ResourcesKey = "PDI"; // The resource manager - private static ResourceManager rm; + private static ResourceManager rm = null!; // This is a helper object used to quickly lock the class when creating the resource manager - private static readonly object syncRoot = new Object(); + private static readonly object syncRoot = new(); #endregion @@ -84,12 +83,7 @@ private static ResourceManager Resources /// "[?:<key>]" if not found. internal static string GetString(string name) { - string s = Resources.GetString(name, null); - - if(s == null) - s = $"[?:{name}]"; - - return s; + return Resources.GetString(name, null) ?? $"[?:{name}]"; } /// diff --git a/Source/EWSPDI/MinutelyFrequency.cs b/Source/EWSPDI/MinutelyFrequency.cs index 34ea98b..3210bcc 100644 --- a/Source/EWSPDI/MinutelyFrequency.cs +++ b/Source/EWSPDI/MinutelyFrequency.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : MinutelyFrequency.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/22/2014 -// Note : Copyright 2003-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a class used to implements the Minutely frequency rules // @@ -36,10 +35,10 @@ internal sealed class MinutelyFrequency : IFrequencyRules /// The start date of the range limiting the instances generated /// The end date of the range limiting the instances generated /// The first instance date or null if there are no more instances - public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, + public RecurDateTime? FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, RecurDateTime to) { - RecurDateTime rdt = new RecurDateTime(start); + RecurDateTime rdt = new(start); int adjust; if(RecurDateTime.Compare(start, from, RecurDateTime.DateTimePart.Hour) < 0) @@ -57,7 +56,9 @@ public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime if(RecurDateTime.Compare(rdt, end, RecurDateTime.DateTimePart.Hour) > 0 || RecurDateTime.Compare(rdt, to, RecurDateTime.DateTimePart.Hour) > 0) + { return null; + } return rdt; } @@ -77,7 +78,9 @@ public bool FindNext(Recurrence r, RecurDateTime end, RecurDateTime to, RecurDat if(RecurDateTime.Compare(last, end, RecurDateTime.DateTimePart.Minute) > 0 || RecurDateTime.Compare(last, to, RecurDateTime.DateTimePart.Minute) > 0) + { return false; + } return true; } diff --git a/Source/EWSPDI/MonthlyFrequency.cs b/Source/EWSPDI/MonthlyFrequency.cs index 97b0fb8..5303f0d 100644 --- a/Source/EWSPDI/MonthlyFrequency.cs +++ b/Source/EWSPDI/MonthlyFrequency.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : MonthlyFrequency.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/22/2014 -// Note : Copyright 2003-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a class used to implements the Monthly frequency rules // @@ -36,12 +35,12 @@ internal sealed class MonthlyFrequency : IFrequencyRules /// The start date of the range limiting the instances generated /// The end date of the range limiting the instances generated /// The first instance date or null if there are no more instances - public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, + public RecurDateTime? FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, RecurDateTime to) { int adjust; - RecurDateTime rdt = new RecurDateTime(start); + RecurDateTime rdt = new(start); // Adjust the date if the starting date is before the limiting range start date if(RecurDateTime.Compare(rdt, from, RecurDateTime.DateTimePart.Month) < 0) @@ -52,7 +51,9 @@ public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime if(RecurDateTime.Compare(rdt, end, RecurDateTime.DateTimePart.Month) > 0 || RecurDateTime.Compare(rdt, to, RecurDateTime.DateTimePart.Month) > 0) + { return null; + } return rdt; } @@ -72,7 +73,9 @@ public bool FindNext(Recurrence r, RecurDateTime end, RecurDateTime to, RecurDat if(RecurDateTime.Compare(last, end, RecurDateTime.DateTimePart.Month) > 0 || RecurDateTime.Compare(last, to, RecurDateTime.DateTimePart.Month) > 0) + { return false; + } return true; } diff --git a/Source/EWSPDI/Period.cs b/Source/EWSPDI/Period.cs index b90ab95..78b321c 100644 --- a/Source/EWSPDI/Period.cs +++ b/Source/EWSPDI/Period.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : Period.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a class that represents a period of time // @@ -71,7 +70,7 @@ public enum PeriodFormat /// The property is updated automatically based on the new value public Duration Duration { - get => new Duration(this.EndDateTime - this.StartDateTime); + get => new(this.EndDateTime - this.StartDateTime); set => this.EndDateTime = this.StartDateTime + value.TimeSpan; } @@ -126,7 +125,7 @@ public Period(DateTime startDateTime, DateTime endDateTime) /// Copy constructor /// /// The period to copy - public Period(Period period) + public Period(Period? period) { if(period != null) { @@ -147,7 +146,7 @@ public Period(Period period) /// format of the string received. /// This is thrown if the specified period string or any of its parts /// are not valid. - public Period(string period) + public Period(string? period) { if(String.IsNullOrWhiteSpace(period)) { @@ -157,7 +156,7 @@ public Period(string period) return; } - string[] parts = period.Split('/'); + string[] parts = period!.Split('/'); if(parts.Length != 2) throw new ArgumentException(LR.GetString("ExPeriodInvalidISOFormat"), nameof(period)); @@ -189,7 +188,7 @@ public Period(string period) /// specified by s, or an empty period object if the conversion failed. This parameter is passed in /// uninitialized. /// True if successfully parsed or false if the value could not be parsed - public static bool TryParse(string period, out Period result) + public static bool TryParse(string? period, out Period result) { try { @@ -219,7 +218,7 @@ public static bool TryParse(string period, out Period result) /// The first period to compare /// The second period to compare /// Returns true if the periods are equal, false if they are not - public static bool Equals(Period p1, Period p2) + public static bool Equals(Period? p1, Period? p2) { if(p1 is null && p2 is null) return true; @@ -235,11 +234,9 @@ public static bool Equals(Period p1, Period p2) /// /// The object to which this instance is compared /// Returns true if the object equals this instance, false if it does not - public override bool Equals(object obj) + public override bool Equals(object? obj) { - Period p = obj as Period; - - if(p == null) + if(obj is not Period p) return false; return (this.StartDateTime == p.StartDateTime && this.EndDateTime == p.EndDateTime); @@ -266,9 +263,11 @@ public override int GetHashCode() public override string ToString() { if(this.Format == PeriodFormat.StartDuration) + { return String.Format(CultureInfo.InvariantCulture, "{0}/{1}", this.StartDateTime.ToUniversalTime().ToString(ISO8601Format.BasicDateTimeUniversal, CultureInfo.InvariantCulture), this.Duration.ToString(Duration.MaxUnit.Weeks)); + } return String.Format(CultureInfo.InvariantCulture, "{0}/{1}", this.StartDateTime.ToUniversalTime().ToString(ISO8601Format.BasicDateTimeUniversal, CultureInfo.InvariantCulture), @@ -289,10 +288,10 @@ public override string ToString() /// Period. public int CompareTo(object obj) { - if(!(obj is Period p)) + if(obj is not Period p) throw new ArgumentException(LR.GetString("ExPeriodBadCompareObject")); - return Period.Compare(this, p); + return Compare(this, p); } /// @@ -302,18 +301,18 @@ public int CompareTo(object obj) /// The second period /// Returns -1 if the first instance is less than the second, 0 if they are equal, or 1 if the /// first instance is greater than the second. - public static int Compare(Period p1, Period p2) + public static int Compare(Period? p1, Period? p2) { if(p1 is null && p2 is null) return 0; - if(!(p1 is null) && p2 is null) + if(p1 is not null && p2 is null) return 1; - if(p1 is null && !(p2 is null)) + if(p1 is null && p2 is not null) return -1; - if(p1.StartDateTime > p2.StartDateTime) + if(p1!.StartDateTime > p2!.StartDateTime) return 1; if(p1.StartDateTime < p2.StartDateTime) @@ -334,9 +333,9 @@ public static int Compare(Period p1, Period p2) /// The first period object /// The second period object /// True if equal, false if not - public static bool operator == (Period p1, Period p2) + public static bool operator == (Period? p1, Period? p2) { - return (Period.Compare(p1, p2) == 0); + return Compare(p1, p2) == 0; } /// @@ -345,9 +344,9 @@ public static int Compare(Period p1, Period p2) /// The first period object /// The second period object /// True if not equal, false if they are equal - public static bool operator != (Period p1, Period p2) + public static bool operator != (Period? p1, Period? p2) { - return (Period.Compare(p1, p2) != 0); + return Compare(p1, p2) != 0; } /// @@ -356,9 +355,9 @@ public static int Compare(Period p1, Period p2) /// The first period object /// The second period object /// True if r1 is less than r2, false if not - public static bool operator < (Period p1, Period p2) + public static bool operator < (Period? p1, Period? p2) { - return (Period.Compare(p1, p2) < 0); + return Compare(p1, p2) < 0; } /// @@ -367,9 +366,9 @@ public static int Compare(Period p1, Period p2) /// The first period object /// The second period object /// True if r1 is greater than r2, false if not - public static bool operator > (Period p1, Period p2) + public static bool operator > (Period? p1, Period? p2) { - return (Period.Compare(p1, p2) > 0); + return Compare(p1, p2) > 0; } /// @@ -378,9 +377,9 @@ public static int Compare(Period p1, Period p2) /// The first period object /// The second period object /// True if r1 is less than or equal to r2, false if not - public static bool operator <= (Period p1, Period p2) + public static bool operator <= (Period? p1, Period? p2) { - return (Period.Compare(p1, p2) <= 0); + return Compare(p1, p2) <= 0; } /// @@ -389,9 +388,9 @@ public static int Compare(Period p1, Period p2) /// The first period object /// The second period object /// True if r1 is greater than or equal to r2, false if not - public static bool operator >= (Period p1, Period p2) + public static bool operator >= (Period? p1, Period? p2) { - return (Period.Compare(p1, p2) >= 0); + return Compare(p1, p2) >= 0; } #endregion } diff --git a/Source/EWSPDI/Properties/AssemblyInfoShared.cs b/Source/EWSPDI/Properties/AssemblyInfoShared.cs index 6d803dc..dfe7108 100644 --- a/Source/EWSPDI/Properties/AssemblyInfoShared.cs +++ b/Source/EWSPDI/Properties/AssemblyInfoShared.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : AssemblyInfo.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/02/2023 -// Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +// Updated : 01/09/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // PDI library common assembly attributes // @@ -56,10 +56,10 @@ // // This is used to set the assembly file version. This will change with each new release. MSIs only support a // Major value between 0 and 255 so we drop the century from the year on this one. -[assembly: AssemblyFileVersion("23.1.2.0")] +[assembly: AssemblyFileVersion("25.1.9.0")] // Common product version // // This may contain additional text to indicate Alpha or Beta states. The version number will always match the // file version above but includes the century on the year. -[assembly: AssemblyInformationalVersion("2023.1.2.0")] +[assembly: AssemblyInformationalVersion("2025.1.9.0")] diff --git a/Source/EWSPDI/ReadMe.txt b/Source/EWSPDI/ReadMe.md similarity index 89% rename from Source/EWSPDI/ReadMe.txt rename to Source/EWSPDI/ReadMe.md index ed8c4d8..dbdc318 100644 --- a/Source/EWSPDI/ReadMe.txt +++ b/Source/EWSPDI/ReadMe.md @@ -1,5 +1,4 @@ -EWSoftware.PDI Library ----------------------- +# EWSoftware.PDI Library This library contains the core set of useful Personal Data Interchange (PDI) and date utility classes for .NET applications. They can be used for calculating holiday dates, recurrences, etc. diff --git a/Source/EWSPDI/RecurDateTime.cs b/Source/EWSPDI/RecurDateTime.cs index 4c0e645..3963f45 100644 --- a/Source/EWSPDI/RecurDateTime.cs +++ b/Source/EWSPDI/RecurDateTime.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RecurDateTime.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a class that contains a date/time object used in the calculation of recurring date/times. // It is different from the standard System.DateTime object in that it can be set to invalid dates which is @@ -232,7 +231,7 @@ public RecurDateTime(RecurDateTime rdt) /// The first date/time to compare /// The second date/time to compare /// Returns true if the date/times are equal, false if they are not - public static bool Equals(RecurDateTime r1, RecurDateTime r2) + public static bool Equals(RecurDateTime? r1, RecurDateTime? r2) { if(r1 is null && r2 is null) return true; @@ -248,15 +247,13 @@ public static bool Equals(RecurDateTime r1, RecurDateTime r2) /// /// The object to which this instance is compared /// Returns true if the object equals this instance, false if it does not - public override bool Equals(object obj) + public override bool Equals(object? obj) { - RecurDateTime r = obj as RecurDateTime; - - if(r == null) + if(obj is not RecurDateTime r) return false; - return (year == r.Year && month == r.Month && day == r.Day && hour == r.Hour && minute == r.Minute && - second == r.Second); + return year == r.Year && month == r.Month && day == r.Day && hour == r.Hour && minute == r.Minute && + second == r.Second; } /// @@ -367,6 +364,7 @@ public void AddDays(int days) } } else + { while(newDay <= 0) { if(month == 0) @@ -379,6 +377,7 @@ public void AddDays(int days) newDay += DateTime.DaysInMonth(year, month + 1); } + } day = newDay; } @@ -520,12 +519,10 @@ public bool IsValidDate() /// RecurDateTime. public int CompareTo(object obj) { - RecurDateTime rd = obj as RecurDateTime; - - if(rd == null) + if(obj is not RecurDateTime rd) throw new ArgumentException(LR.GetString("ExRDTBadCompareObject")); - return RecurDateTime.Compare(this, rd); + return Compare(this, rd); } /// @@ -536,18 +533,18 @@ public int CompareTo(object obj) /// Returns -1 if the first instance is less than the second, 0 if they are equal, or 1 if the /// first instance is greater than the second. /// There are two versions of this method - public static int Compare(RecurDateTime r1, RecurDateTime r2) + public static int Compare(RecurDateTime? r1, RecurDateTime? r2) { if(r1 is null && r2 is null) return 0; - if(!(r1 is null) && r2 is null) + if(r1 is not null && r2 is null) return 1; - if(r1 is null && !(r2 is null)) + if(r1 is null && r2 is not null) return -1; - if(r1.Year < r2.Year) + if(r1!.Year < r2!.Year) return -1; if(r1.Year > r2.Year) @@ -595,18 +592,18 @@ public static int Compare(RecurDateTime r1, RecurDateTime r2) /// The part up to which comparisons are made. Parts smaller than this are ignored. /// Returns -1 if the first instance is less than the second, 0 if they are equal, or 1 if the /// first instance is greater than the second. - public static int Compare(RecurDateTime r1, RecurDateTime r2, DateTimePart part) + public static int Compare(RecurDateTime? r1, RecurDateTime? r2, DateTimePart part) { if(r1 is null && r2 is null) return 0; - if(!(r1 is null) && r2 is null) + if(r1 is not null && r2 is null) return 1; - if(r1 is null && !(r2 is null)) + if(r1 is null && r2 is not null) return -1; - if(r1.Year < r2.Year) + if(r1!.Year < r2!.Year) return -1; if(r1.Year > r2.Year) @@ -666,9 +663,9 @@ public static int Compare(RecurDateTime r1, RecurDateTime r2, DateTimePart part) /// The first date/time object /// The second date/time object /// True if equal, false if not - public static bool operator == (RecurDateTime r1, RecurDateTime r2) + public static bool operator == (RecurDateTime? r1, RecurDateTime? r2) { - return (RecurDateTime.Compare(r1, r2) == 0); + return Compare(r1, r2) == 0; } /// @@ -677,9 +674,9 @@ public static int Compare(RecurDateTime r1, RecurDateTime r2, DateTimePart part) /// The first date/time object /// The second date/time object /// True if not equal, false if they are equal - public static bool operator != (RecurDateTime r1, RecurDateTime r2) + public static bool operator != (RecurDateTime? r1, RecurDateTime? r2) { - return (RecurDateTime.Compare(r1, r2) != 0); + return Compare(r1, r2) != 0; } /// @@ -688,9 +685,9 @@ public static int Compare(RecurDateTime r1, RecurDateTime r2, DateTimePart part) /// The first date/time object /// The second date/time object /// True if r1 is less than r2, false if not - public static bool operator < (RecurDateTime r1, RecurDateTime r2) + public static bool operator < (RecurDateTime? r1, RecurDateTime? r2) { - return (RecurDateTime.Compare(r1, r2) < 0); + return Compare(r1, r2) < 0; } /// @@ -699,9 +696,9 @@ public static int Compare(RecurDateTime r1, RecurDateTime r2, DateTimePart part) /// The first date/time object /// The second date/time object /// True if r1 is greater than r2, false if not - public static bool operator > (RecurDateTime r1, RecurDateTime r2) + public static bool operator > (RecurDateTime? r1, RecurDateTime? r2) { - return (RecurDateTime.Compare(r1, r2) > 0); + return Compare(r1, r2) > 0; } /// @@ -710,9 +707,9 @@ public static int Compare(RecurDateTime r1, RecurDateTime r2, DateTimePart part) /// The first date/time object /// The second date/time object /// True if r1 is less than or equal to r2, false if not - public static bool operator <= (RecurDateTime r1, RecurDateTime r2) + public static bool operator <= (RecurDateTime? r1, RecurDateTime? r2) { - return (RecurDateTime.Compare(r1, r2) <= 0); + return Compare(r1, r2) <= 0; } /// @@ -721,9 +718,9 @@ public static int Compare(RecurDateTime r1, RecurDateTime r2, DateTimePart part) /// The first date/time object /// The second date/time object /// True if r1 is greater than or equal to r2, false if not - public static bool operator >= (RecurDateTime r1, RecurDateTime r2) + public static bool operator >= (RecurDateTime? r1, RecurDateTime? r2) { - return (RecurDateTime.Compare(r1, r2) >= 0); + return Compare(r1, r2) >= 0; } #endregion } diff --git a/Source/EWSPDI/RecurOptsDataSource.cs b/Source/EWSPDI/RecurOptsDataSource.cs index 16293db..aafd644 100644 --- a/Source/EWSPDI/RecurOptsDataSource.cs +++ b/Source/EWSPDI/RecurOptsDataSource.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RecurOptsDataSource.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a helper class that can be used to obtain a list of values suitable for binding to a combo // box, list box, etc. The Windows Forms user controls use these to bind the values and descriptions for the @@ -39,13 +38,14 @@ public static class RecurOptsDataSource /// /// An interface reference suitable for data binding. The underlying object /// is a containing a set of objects. - public static IList DayOccurrences => new List(new[] { + public static IList DayOccurrences => new List( + [ new ListItem(DayOccurrence.First, LR.EnumDesc(DayOccurrence.First)), new ListItem(DayOccurrence.Second, LR.EnumDesc(DayOccurrence.Second)), new ListItem(DayOccurrence.Third, LR.EnumDesc(DayOccurrence.Third)), new ListItem(DayOccurrence.Fourth, LR.EnumDesc(DayOccurrence.Fourth)), new ListItem(DayOccurrence.Last, LR.EnumDesc(DayOccurrence.Last)) - }); + ]); /// /// This read-only property returns a data source containing the days of the week based on @@ -59,7 +59,8 @@ public static IList DaysOfWeek { string[] dayNames = CultureInfo.CurrentCulture.DateTimeFormat.DayNames; - return new List(new[] { + return new List( + [ new ListItem(PDI.DaysOfWeek.Sunday, dayNames[0]), new ListItem(PDI.DaysOfWeek.Monday, dayNames[1]), new ListItem(PDI.DaysOfWeek.Tuesday, dayNames[2]), @@ -70,7 +71,7 @@ public static IList DaysOfWeek new ListItem(PDI.DaysOfWeek.Weekdays, LR.EnumDesc(PDI.DaysOfWeek.Weekdays)), new ListItem(PDI.DaysOfWeek.Weekends, LR.EnumDesc(PDI.DaysOfWeek.Weekends)), new ListItem(PDI.DaysOfWeek.EveryDay, LR.EnumDesc(PDI.DaysOfWeek.EveryDay)) - }); + ]); } } diff --git a/Source/EWSPDI/Recurrence.cs b/Source/EWSPDI/Recurrence.cs index 1f23088..a92a3d2 100644 --- a/Source/EWSPDI/Recurrence.cs +++ b/Source/EWSPDI/Recurrence.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : Recurrence.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/23/2018 -// Note : Copyright 2003-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a class that can be used to generate recurring date/time sequences based on a pattern // defined by the RRULE property in the iCalender 2.0 specification. @@ -51,14 +50,14 @@ public class Recurrence : ISerializable, IXmlSerializable //===================================================================== // Regular expressions used for parsing - private static Regex reSplit = new Regex(@"\s"); - private static Regex reFreqPresent = new Regex("FREQ=", RegexOptions.IgnoreCase); - private static Regex reParse = new Regex("(?:(?:R|EX)RULE:)?(?:(?[^=;]+)=(?[^;]*))?"); - private static Regex reDays = new Regex(@"(?[\-0-9]*)?(?[A-Z]*)"); + private static readonly Regex reSplit = new(@"\s"); + private static readonly Regex reFreqPresent = new("FREQ=", RegexOptions.IgnoreCase); + private static readonly Regex reParse = new("(?:(?:R|EX)RULE:)?(?:(?[^=;]+)=(?[^;]*))?"); + private static readonly Regex reDays = new(@"(?[\-0-9]*)?(?[A-Z]*)"); // This is used to convert the days of the week to their string form. This is convenient for generating // its iCalendar representation. - private static readonly string[] abbrevDays = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" }; + private static readonly string[] abbrevDays = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"]; private DateTime startDate; @@ -66,8 +65,6 @@ public class Recurrence : ISerializable, IXmlSerializable private DateTime untilDate; private int maxOccur; - private bool canOccurOnHoliday; - private RecurFrequency frequency; private int interval; @@ -75,12 +72,12 @@ public class Recurrence : ISerializable, IXmlSerializable private DayOfWeek weekStart; // Collections of unique integer values representing the BY* rules - private UniqueIntegerCollection byMonth, byWeekNo, byYearDay, byMonthDay, byHour, byMinute, bySecond, - bySetPos; + private readonly UniqueIntegerCollection byMonth, byWeekNo, byYearDay, byMonthDay, byHour, byMinute, + bySecond, bySetPos; // A collection of BYDAY rules. These can be week days or instances of weekdays (i.e. 1st Monday, second // to last Friday, etc). - private DayInstanceCollection byDay; + private readonly DayInstanceCollection byDay; // Arrays for some of the above. These are used during the recurrence calculation for speed. They are // marked internal so that the filter functions can access them directly. @@ -92,19 +89,15 @@ public class Recurrence : ISerializable, IXmlSerializable internal int weekdayOffset; // This is used to reference the frequency rules used to expand the recurrence - private IFrequencyRules freqRules; + private IFrequencyRules? freqRules; // These are used to contain holidays for the CanOccurOnHoliday option when it is set to false. Note // that the holiday collection is static and will be shared by all Recurrence instances. - private static HolidayCollection holidays; - - // These are used to contain holidays for the CanOccurOnHoliday option when it is set to false on - // a per-recurrence instance basis. - private HolidayCollection instanceHolidays; - private HashSet holDates; + private static HolidayCollection holidays = null!; + private HashSet? holDates; // This is used to preserve custom properties not supported by this class - private StringCollection customProps; + private readonly StringCollection customProps; #endregion @@ -204,17 +197,7 @@ public int MaximumOccurrences /// on holiday dates. /// /// - public bool CanOccurOnHoliday - { - get => canOccurOnHoliday; - set - { - canOccurOnHoliday = value; - - if(!value && holidays == null) - holidays = new HolidayCollection(); - } - } + public bool CanOccurOnHoliday { get; set; } /// /// This property is used to set or get the current recurrence frequency @@ -390,8 +373,7 @@ public static HolidayCollection Holidays { get { - if(holidays == null) - holidays = new HolidayCollection(); + holidays ??= []; return holidays; } @@ -404,11 +386,7 @@ public static HolidayCollection Holidays /// Note that the holiday list is not static and will not be shared amongst all instances of the /// Recurrence classes. /// - public HolidayCollection InstanceHolidays - { - get => instanceHolidays; - set => instanceHolidays = value; - } + public HolidayCollection? InstanceHolidays { get; set; } /// /// This returns a set of custom properties (if any) found when the recurrence properties where parsed @@ -436,8 +414,8 @@ public Recurrence() byMinute = new UniqueIntegerCollection(0, 59, true); bySecond = new UniqueIntegerCollection(0, 59, true); bySetPos = new UniqueIntegerCollection(-366, 366, false); - byDay = new DayInstanceCollection(); - customProps = new StringCollection(); + byDay = []; + customProps = []; isSecondUsed = new bool[60]; isMinuteUsed = new bool[60]; @@ -682,7 +660,7 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) RecurDateTime rdt; int idx, count, lastYear = -1; - DateTimeCollection dcDates = new DateTimeCollection(); + DateTimeCollection dcDates = []; // If undefined or if the requested range is outside that of the recurrence, don't bother. Just // return an empty collection. Note that for defined recurrences that use a count, we'll always @@ -690,16 +668,14 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) if(frequency == RecurFrequency.Undefined || startDate > toDate || untilDate < fromDate) return dcDates; - RecurDateTime start = new RecurDateTime(startDate), end = new RecurDateTime(untilDate), - from = new RecurDateTime(fromDate), to = new RecurDateTime(toDate); - - RecurDateTime current = freqRules.FindStart(this, start, end, from, to); + RecurDateTime start = new(startDate), end = new(untilDate), from = new(fromDate), to = new(toDate); + RecurDateTime? current = freqRules?.FindStart(this, start, end, from, to); // If there's nothing to generate, stop now if(current == null) return dcDates; - rdtc = new RecurDateTimeCollection(); + rdtc = []; // Initialize the filtering arrays. These help speed up the filtering process by letting us do one // look up as opposed to comparing all elements in the collection. @@ -714,41 +690,59 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) Array.Clear(isMonthUsed, 0, isMonthUsed.Length); if(bySecond.Count != 0) + { foreach(int second in bySecond) isSecondUsed[second] = true; + } if(byMinute.Count != 0) + { foreach(int minute in byMinute) isMinuteUsed[minute] = true; + } if(byHour.Count != 0) + { foreach(int hour in byHour) isHourUsed[hour] = true; + } if(byMonth.Count != 0) + { foreach(int month in byMonth) isMonthUsed[month - 1] = true; + } // When filtering, the instance is ignored if(byDay.Count != 0) + { foreach(DayInstance di in byDay) isDayUsed[(int)di.DayOfWeek] = true; + } // Negative days are from the end of the month if(byMonthDay.Count != 0) + { foreach(int monthDay in byMonthDay) + { if(monthDay > 0) isMonthDayUsed[monthDay] = true; else isNegMonthDayUsed[0 - monthDay] = true; + } + } // Negative days are from the end of the year if(byYearDay.Count != 0) + { foreach(int yearDay in byYearDay) + { if(yearDay > 0) isYearDayUsed[yearDay] = true; else isNegYearDayUsed[0 - yearDay] = true; + } + } do { @@ -770,7 +764,8 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) break; case RecurFrequency.Monthly: - if(freqRules.ByMonth(this, rdtc) != 0) + if(freqRules!.ByMonth(this, rdtc) != 0) + { if(freqRules.ByYearDay(this, rdtc) != 0) { // If BYMONTHDAY and BYDAY are specified, expand by month day and filter by day. @@ -779,6 +774,7 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) if(byMonthDay.Count != 0 && byDay.Count != 0) { if(Expand.ByMonthDay(this, rdtc) != 0) + { if(Filter.ByDay(this, rdtc) != 0) { // These always expand if used @@ -786,9 +782,12 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) Expand.ByMinute(this, rdtc); Expand.BySecond(this, rdtc); } + } } else + { if(Expand.ByMonthDay(this, rdtc) != 0) + { if(freqRules.ByDay(this, rdtc) != 0) { // These always expand if used @@ -796,19 +795,32 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) Expand.ByMinute(this, rdtc); Expand.BySecond(this, rdtc); } + } + } } + } break; default: // Everything else is fairly straightforward. We just expand or filter based on the // frequency type and what rules are specified. - if(freqRules.ByMonth(this, rdtc) != 0) + if(freqRules!.ByMonth(this, rdtc) != 0) + { if(freqRules.ByYearDay(this, rdtc) != 0) + { if(freqRules.ByMonthDay(this, rdtc) != 0) + { if(freqRules.ByDay(this, rdtc) != 0) + { if(freqRules.ByHour(this, rdtc) != 0) + { if(freqRules.ByMinute(this, rdtc) != 0) freqRules.BySecond(this, rdtc); + } + } + } + } + } break; } @@ -829,13 +841,13 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) } // Discard it if it falls on a holiday - if(!canOccurOnHoliday) + if(!this.CanOccurOnHoliday) { // If this is the first call or the year changes, get the holidays in the date's year // and the next year. if(holDates == null || lastYear != rdt.Year) { - var holidayCollection = instanceHolidays ?? holidays; + var holidayCollection = this.InstanceHolidays ?? Holidays; holDates = new HashSet(holidayCollection.HolidaysBetween(rdt.Year, rdt.Year + 1)); lastYear = rdt.Year; } @@ -877,14 +889,20 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) idx = nPos - 1; if(idx >= 0 && idx < rdtc.Count) + { if(rdtc[idx] >= start && rdtc[idx] <= end && rdtc[idx] >= from && rdtc[idx] <= to) dcDates.Add(rdtc[idx].ToDateTime()); + } } } else + { for(idx = 0; idx < rdtc.Count; idx++) + { if(rdtc[idx] >= start && rdtc[idx] <= end && rdtc[idx] >= from && rdtc[idx] <= to) dcDates.Add(rdtc[idx].ToDateTime()); + } + } // Handle MaxOccurrences property. Note that if it's used, it is assumed that the limiting // range starts at the recurrence start. Otherwise, we have no way of knowing how many @@ -894,7 +912,7 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) } // Loop until the end of the recurrence or the range - } while(freqRules.FindNext(this, end, to, current) && (maxOccur == 0 || dcDates.Count < maxOccur)); + } while(freqRules!.FindNext(this, end, to, current) && (maxOccur == 0 || dcDates.Count < maxOccur)); // Sort the collection one last time. There's no guaranteed order of selection if BYSETPOS was used. dcDates.Sort(true); @@ -911,7 +929,7 @@ private DateTimeCollection GenerateInstances(DateTime fromDate, DateTime toDate) /// private void ExpandYearly(RecurDateTimeCollection dates) { - RecurDateTimeCollection rdtcMonth = null, rdtcMoDay = null, rdtcWeek = null, rdtcYrDay = null, + RecurDateTimeCollection? rdtcMonth = null, rdtcMoDay = null, rdtcWeek = null, rdtcYrDay = null, rdtcDay = null; bool isExpanded = false; @@ -923,7 +941,7 @@ private void ExpandYearly(RecurDateTimeCollection dates) // Expand by month isExpanded = true; rdtcMonth = new RecurDateTimeCollection(dates); - freqRules.ByMonth(this, rdtcMonth); + freqRules!.ByMonth(this, rdtcMonth); // If BYMONTHDAY and BYDAY are both specified, we need to expand by month day and then filter by // day. If we expand by day alone, note that we do so only in the months specified in the @@ -944,7 +962,7 @@ private void ExpandYearly(RecurDateTimeCollection dates) // Expand by month day if specified without any by month rule part isExpanded = true; rdtcMoDay = new RecurDateTimeCollection(dates); - freqRules.ByMonthDay(this, rdtcMoDay); + freqRules!.ByMonthDay(this, rdtcMoDay); } // As long as by week number isn't specified either, we'll expand the by day rule here too @@ -952,7 +970,7 @@ private void ExpandYearly(RecurDateTimeCollection dates) { isExpanded = true; rdtcDay = new RecurDateTimeCollection(dates); - freqRules.ByDay(this, rdtcDay); + freqRules!.ByDay(this, rdtcDay); } } @@ -961,7 +979,7 @@ private void ExpandYearly(RecurDateTimeCollection dates) // Expand by week number isExpanded = true; rdtcWeek = new RecurDateTimeCollection(dates); - freqRules.ByWeekNo(this, rdtcWeek); + freqRules!.ByWeekNo(this, rdtcWeek); // Expand by days of the week in those weeks Expand.ByDayInWeeks(this, rdtcWeek); @@ -972,7 +990,7 @@ private void ExpandYearly(RecurDateTimeCollection dates) // Expand by year day isExpanded = true; rdtcYrDay = new RecurDateTimeCollection(dates); - freqRules.ByYearDay(this, rdtcYrDay); + freqRules!.ByYearDay(this, rdtcYrDay); } // Combine the various expansions. If nothing was done, leave the original date in the collection. @@ -1033,13 +1051,13 @@ public void Reset() /// vCalendar format, only the basic recurrence rule grammar is supported. Full support is provided for /// the iCalendar format. /// - public void Parse(string recur) + public void Parse(string? recur) { string property, value; string[] values; int dayIdx; - canOccurOnHoliday = true; + this.CanOccurOnHoliday = true; untilDate = DateTime.MaxValue; @@ -1059,18 +1077,18 @@ public void Parse(string recur) byDay.Clear(); customProps.Clear(); - if(recur == null || recur.Length == 0) + if(String.IsNullOrWhiteSpace(recur)) return; // If there is no frequency, try parsing it in vCalendar format if(!reFreqPresent.IsMatch(recur)) { - this.ParseVCalendar(recur); + this.ParseVCalendar(recur!); return; } // Split the string into its properties - MatchCollection matches = reParse.Matches(recur.ToUpperInvariant()); + MatchCollection matches = reParse.Matches(recur!.ToUpperInvariant()); foreach(Match m in matches) { @@ -1206,10 +1224,10 @@ public void Parse(string recur) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is Recurrence r)) + if(obj is not Recurrence r) return false; - return (this == r || this.ToString() == r.ToString()); + return this == r || this.ToString() == r.ToString(); } /// @@ -1229,7 +1247,7 @@ public override int GetHashCode() /// Since the start date is not part of the recurrence for iCalendar, it is omitted. public override string ToString() { - StringBuilder sb = new StringBuilder(256); + StringBuilder sb = new(256); sb.AppendFormat("FREQ={0}", this.Frequency.ToString().ToUpperInvariant()); @@ -1239,9 +1257,13 @@ public override string ToString() if(this.MaximumOccurrences != 0) sb.AppendFormat(";COUNT={0}", this.MaximumOccurrences); else + { if(this.RecurUntil != DateTime.MaxValue) + { sb.AppendFormat(";UNTIL={0}", this.RecurUntil.ToUniversalTime().ToString( ISO8601Format.BasicDateTimeUniversal, CultureInfo.InvariantCulture)); + } + } if(this.WeekStart != DayOfWeek.Monday) sb.AppendFormat(";WKST={0}", abbrevDays[(int)this.WeekStart]); @@ -1340,11 +1362,13 @@ public override string ToString() sb.Append(";X-EWSOFTWARE-OCCURONHOL=0"); if(customProps.Count != 0) + { foreach(string s in customProps) { sb.Append(';'); sb.Append(s); } + } return sb.ToString(); } @@ -1370,7 +1394,7 @@ public string ToStringWithStartDateTime() /// Any options that are not part of the basic grammar are ignored. public string ToVCalendarString() { - StringBuilder sb = new StringBuilder(256); + StringBuilder sb = new(256); switch(this.Frequency) { @@ -1382,8 +1406,10 @@ public string ToVCalendarString() sb.AppendFormat("W{0}", this.Interval); if(byDay.Count != 0) + { foreach(DayInstance d in byDay) sb.AppendFormat(" {0}", abbrevDays[(int)d.DayOfWeek]); + } break; case RecurFrequency.Monthly: @@ -1392,10 +1418,12 @@ public string ToVCalendarString() sb.AppendFormat("MD{0}", this.Interval); foreach(int day in byMonthDay) + { if(day < 0) sb.AppendFormat(" {0}-", day * -1); else sb.AppendFormat(" {0}", day); + } } else { @@ -1407,16 +1435,20 @@ public string ToVCalendarString() if(d.Instance == 0) { foreach(int p in bySetPos) + { if(p < 0) sb.AppendFormat(" {0}- {1}", p * -1, abbrevDays[(int)d.DayOfWeek]); else sb.AppendFormat(" {0}+ {1}", p, abbrevDays[(int)d.DayOfWeek]); + } } else + { if(d.Instance < 0) sb.AppendFormat(" {0}- {1}", d.Instance * -1, abbrevDays[(int)d.DayOfWeek]); else sb.AppendFormat(" {0}+ {1}", d.Instance, abbrevDays[(int)d.DayOfWeek]); + } } } break; @@ -1436,10 +1468,12 @@ public string ToVCalendarString() // There don't appear to be any examples that suggest a negative year day value is // supported but we'll assume it is. foreach(int day in byYearDay) + { if(day < 0) sb.AppendFormat(" {0}-", day * -1); else sb.AppendFormat(" {0}", day); + } } break; @@ -1449,15 +1483,21 @@ public string ToVCalendarString() } if(sb.Length > 0) + { if(this.MaximumOccurrences != 0) sb.AppendFormat(" #{0}", this.MaximumOccurrences); else + { if(this.RecurUntil == DateTime.MaxValue) sb.Append(" #0"); // Forever else + { sb.AppendFormat(" {0}", this.RecurUntil.ToUniversalTime().ToString(ISO8601Format.BasicDateTimeUniversal, CultureInfo.InvariantCulture)); + } + } + } return sb.ToString(); } @@ -1657,10 +1697,12 @@ public void RecurMonthly(DayOccurrence occur, DaysOfWeek daysOfWeek, int recurIn byDay[0].Instance = (int)occur; } else + { if(occur == DayOccurrence.Last) bySetPos.Add(-1); else bySetPos.Add((int)occur); + } } /// @@ -1777,10 +1819,12 @@ public void RecurYearly(DayOccurrence occur, DaysOfWeek daysOfWeek, int month, i byDay[0].Instance = (int)occur; } else + { if(occur == DayOccurrence.Last) bySetPos.Add(-1); else bySetPos.Add((int)occur); + } } /// @@ -1847,11 +1891,13 @@ public DateTimeCollection InstancesBetween(DateTime fromDate, DateTime toDate) // Filter out dates outside the requested range for(idx = 0; idx < dtc.Count; idx++) + { if(dtc[idx] < fromDate || dtc[idx] > toDate) { dtc.RemoveAt(idx); idx--; } + } } else dtc = GenerateInstances(fromDate, toDate); @@ -1891,11 +1937,13 @@ public DateTime NextInstance(DateTime fromDate, bool onlyAfter) // Filter out dates outside the requested range for(idx = 0; idx < dtc.Count; idx++) + { if(dtc[idx] >= fromDate) { instance = dtc[idx]; break; } + } } else { @@ -1927,6 +1975,7 @@ public DateTime NextInstance(DateTime fromDate, bool onlyAfter) while(fromDate < untilDate) { dtc = GenerateInstances(fromDate, fromDate.Add(ts)); + if(dtc.Count > 0) { instance = dtc[0]; @@ -1974,8 +2023,7 @@ public RecurrenceEnumerator GetEnumerator() public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { // Since the string form is the most compact, use that - if(info != null) - info.AddValue("Recurrence", this.ToStringWithStartDateTime()); + info?.AddValue("Recurrence", this.ToStringWithStartDateTime()); } #endregion @@ -1988,15 +2036,9 @@ public virtual void GetObjectData(SerializationInfo info, StreamingContext conte /// The XML schema public XmlSchema GetSchema() { - XmlSchema xs = null; - - using(StreamReader sr = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream( - "EWSoftware.PDI.Schemas.Recurrence.xsd"))) - { - xs = XmlSchema.Read(sr, null); - } - - return xs; + using StreamReader sr = new(Assembly.GetExecutingAssembly().GetManifestResourceStream( + "EWSoftware.PDI.Schemas.Recurrence.xsd")); + return XmlSchema.Read(sr, null); } /// @@ -2007,20 +2049,18 @@ public XmlSchema GetSchema() /// RRULE. As such, when serializing we'll use that compact form rather than a more verbose form with /// the various properties all spelled out with separate entities. /// - public void WriteXml(XmlWriter writer) + public void WriteXml(XmlWriter? writer) { - if(writer != null) - writer.WriteString(this.ToStringWithStartDateTime()); + writer?.WriteString(this.ToStringWithStartDateTime()); } /// /// This is called to deserialize the instance from XML /// /// The XML reader from which the instance is deserialized - public void ReadXml(XmlReader reader) + public void ReadXml(XmlReader? reader) { - if(reader != null) - this.Parse(reader.ReadString()); + this.Parse(reader?.ReadString()); } #endregion @@ -2069,6 +2109,7 @@ public bool IsAdvancedPattern isAdvanced = true; } else + { if(byDayCount == 5) { // Any interval other than one makes it advanced @@ -2078,24 +2119,31 @@ public bool IsAdvancedPattern { // If it's just weekdays, it's still simple for(idx = 0; idx < 5; idx++) + { if(this.ByDay[idx].Instance != 0 || this.ByDay[idx].DayOfWeek == DayOfWeek.Saturday || this.ByDay[idx].DayOfWeek == DayOfWeek.Sunday) { isAdvanced = true; } + } } } else + { if(byDayCount != 0) isAdvanced = true; + } + } break; case RecurFrequency.Weekly: // Anything but an interval and ByDay on this is advanced if(byMonthCount + byYearDayCount + byMonthDayCount + byHourCount + byMinuteCount + bySecondCount + bySetPosCount != 0) + { isAdvanced = true; + } break; case RecurFrequency.Monthly: @@ -2104,6 +2152,7 @@ public bool IsAdvancedPattern if(byMonthCount + byYearDayCount + byHourCount + byMinuteCount + bySecondCount != 0) isAdvanced = true; else + { if(byDayCount < 2) { if((byDayCount == 0 && byMonthDayCount != 1) || @@ -2121,6 +2170,7 @@ public bool IsAdvancedPattern count = 0; foreach(DayInstance di in this.ByDay) + { switch(di.DayOfWeek) { case DayOfWeek.Sunday: @@ -2158,6 +2208,7 @@ public bool IsAdvancedPattern count++; break; } + } // If not EveryDay, Weekdays, Weekends, or a single day, it's advanced if(bySetPosCount != 1 || byMonthDayCount != 0 || (count > 1 && @@ -2167,6 +2218,7 @@ public bool IsAdvancedPattern isAdvanced = true; } } + } break; case RecurFrequency.Yearly: @@ -2178,6 +2230,7 @@ public bool IsAdvancedPattern isAdvanced = true; } else + { if(byDayCount < 2) { if((byDayCount == 0 && byMonthDayCount != 1) || (byDayCount == 1 && @@ -2194,6 +2247,7 @@ public bool IsAdvancedPattern count = 0; foreach(DayInstance di in this.ByDay) + { switch(di.DayOfWeek) { case DayOfWeek.Sunday: @@ -2231,6 +2285,7 @@ public bool IsAdvancedPattern count++; break; } + } // If not EveryDay, Weekdays, Weekends, or a single day, it's advanced if(bySetPosCount != 1 || byMonthDayCount != 0 || (count > 1 && @@ -2240,6 +2295,7 @@ public bool IsAdvancedPattern isAdvanced = true; } } + } break; } @@ -2277,8 +2333,10 @@ public string ToDescription() // Note the week start if it will be relevant if(interval > 1 && byDay.Count != 0) + { weekStartDesc = LR.GetString("RDWeekStart", CultureInfo.CurrentCulture.DateTimeFormat.DayNames[(int)weekStart]); + } break; case RecurFrequency.Daily: @@ -2305,13 +2363,15 @@ public string ToDescription() if(untilDate == DateTime.MaxValue && maxOccur == 0) range = LR.GetString("RDForever"); else + { if(maxOccur != 0) range = LR.GetString("RDMaxOccur", maxOccur); else range = LR.GetString("RDRecurUntil", untilDate); + } // Note if instances cannot occur on holidays - if(!canOccurOnHoliday) + if(!this.CanOccurOnHoliday) holidayDesc = LR.GetString("RDNoHolidays"); return desc + range + weekStartDesc + holidayDesc; @@ -2322,7 +2382,7 @@ public string ToDescription() /// private string ToWeeklyDescription() { - StringBuilder sb = new StringBuilder(LR.GetString("RDWeekly", interval), 256); + StringBuilder sb = new(LR.GetString("RDWeekly", interval), 256); if(byDay.Count != 0) { @@ -2337,13 +2397,15 @@ private string ToWeeklyDescription() if(idx < byDay.Count - 2) sb.Append(", "); else + { if(idx < byDay.Count - 1) { if(idx != 0) - sb.Append(","); + sb.Append(','); sb.Append(LR.GetString("RDAnd")); } + } } } @@ -2375,6 +2437,7 @@ private string ToMonthlyDescription() // Figure out days used foreach(DayInstance di in byDay) + { switch(di.DayOfWeek) { case DayOfWeek.Sunday: @@ -2405,6 +2468,7 @@ private string ToMonthlyDescription() rd |= DaysOfWeek.Saturday; break; } + } // If not EveryDay, Weekdays, or Weekends, force it to a single day of the week if(rd == DaysOfWeek.None || (rd != DaysOfWeek.EveryDay && rd != DaysOfWeek.Weekdays && @@ -2431,8 +2495,10 @@ private string ToYearlyDescription() int occurrence; if(byDay.Count == 0) + { return LR.GetString("RDYearlyDayX", CultureInfo.CurrentCulture.DateTimeFormat.MonthNames[ byMonth[0] - 1], byMonthDay[0], DayInstance.NumericSuffix(byMonthDay[0]), interval); + } // If it's a single day, use ByDay. If it's a combination, use ByDay with BySetPos. if(byDay.Count == 1) @@ -2449,6 +2515,7 @@ private string ToYearlyDescription() // Figure out days used foreach(DayInstance di in byDay) + { switch(di.DayOfWeek) { case DayOfWeek.Sunday: @@ -2479,6 +2546,7 @@ private string ToYearlyDescription() rd |= DaysOfWeek.Saturday; break; } + } // If not EveryDay, Weekdays, or Weekends, force it to a single day of the week if(rd == DaysOfWeek.None || (rd != DaysOfWeek.EveryDay && rd != DaysOfWeek.Weekdays && @@ -2502,8 +2570,8 @@ private string ToYearlyDescription() /// private string ToAdvancedDescription() { - StringBuilder sb = new StringBuilder(256); - string weekStartDesc = null; + StringBuilder sb = new(256); + string? weekStartDesc = null; bool addComma = false; int idx; @@ -2515,8 +2583,10 @@ private string ToAdvancedDescription() // Note the week start if it will be relevant if(byWeekNo.Count != 0) + { weekStartDesc = LR.GetString("RDWeekStart", CultureInfo.CurrentCulture.DateTimeFormat.DayNames[(int)weekStart]); + } break; case RecurFrequency.Monthly: @@ -2528,8 +2598,10 @@ private string ToAdvancedDescription() // Note the week start if it will be relevant if(interval > 1 && byDay.Count != 0) + { weekStartDesc = LR.GetString("RDWeekStart", CultureInfo.CurrentCulture.DateTimeFormat.DayNames[(int)weekStart]); + } break; case RecurFrequency.Daily: @@ -2553,17 +2625,19 @@ private string ToAdvancedDescription() if(untilDate == DateTime.MaxValue && maxOccur == 0) sb.Append(LR.GetString("RDForever")); else + { if(maxOccur != 0) sb.Append(LR.GetString("RDMaxOccur", maxOccur)); else sb.Append(LR.GetString("RDRecurUntil", untilDate)); + } // Note if the week start is different if(weekStartDesc != null) sb.Append(weekStartDesc); // Note if instances cannot occur on holidays - if(!canOccurOnHoliday) + if(!this.CanOccurOnHoliday) sb.Append(LR.GetString("RDNoHolidays")); else sb.Append('.'); @@ -2589,18 +2663,20 @@ private string ToAdvancedDescription() if(idx < byMonth.Count - 2) sb.Append(", "); else + { if(idx < byMonth.Count - 1) { if(idx != 0) - sb.Append(","); + sb.Append(','); sb.Append(LR.GetString("RDAnd")); } + } } - Recurrence.AddIntegerCollection(sb, byWeekNo, "RDByWeekNo", ref addComma); - Recurrence.AddIntegerCollection(sb, byYearDay, "RDByYearDay", ref addComma); - Recurrence.AddIntegerCollection(sb, byMonthDay, "RDByMonthDay", ref addComma); + AddIntegerCollection(sb, byWeekNo, "RDByWeekNo", ref addComma); + AddIntegerCollection(sb, byYearDay, "RDByYearDay", ref addComma); + AddIntegerCollection(sb, byMonthDay, "RDByMonthDay", ref addComma); string[] dayNames = CultureInfo.CurrentCulture.DateTimeFormat.DayNames; @@ -2609,7 +2685,7 @@ private string ToAdvancedDescription() if(idx == 0) { if(addComma) - sb.Append(","); + sb.Append(','); else addComma = true; @@ -2624,21 +2700,23 @@ private string ToAdvancedDescription() if(idx < byDay.Count - 2) sb.Append(", "); else + { if(idx < byDay.Count - 1) { if(idx != 0) - sb.Append(","); + sb.Append(','); sb.Append(LR.GetString("RDAnd")); } + } } - Recurrence.AddIntegerCollection(sb, byHour, "RDByHour", ref addComma); - Recurrence.AddIntegerCollection(sb, byMinute, "RDByMinute", ref addComma); - Recurrence.AddIntegerCollection(sb, bySecond, "RDBySecond", ref addComma); - Recurrence.AddIntegerCollection(sb, bySetPos, "RDBySetPos", ref addComma); + AddIntegerCollection(sb, byHour, "RDByHour", ref addComma); + AddIntegerCollection(sb, byMinute, "RDByMinute", ref addComma); + AddIntegerCollection(sb, bySecond, "RDBySecond", ref addComma); + AddIntegerCollection(sb, bySetPos, "RDBySetPos", ref addComma); - sb.Append("."); + sb.Append('.'); } return sb.ToString(); @@ -2655,7 +2733,7 @@ private static void AddIntegerCollection(StringBuilder sb, UniqueIntegerCollecti if(idx == 0) { if(addComma) - sb.Append(","); + sb.Append(','); else addComma = true; @@ -2678,13 +2756,15 @@ private static void AddIntegerCollection(StringBuilder sb, UniqueIntegerCollecti if(idx < uic.Count - 2) sb.Append(", "); else + { if(idx < uic.Count - 1) { if(idx != 0) - sb.Append(","); + sb.Append(','); sb.Append(LR.GetString("RDAnd")); } + } } if(uic.Count != 0) diff --git a/Source/EWSPDI/RecurrenceEnumerator.cs b/Source/EWSPDI/RecurrenceEnumerator.cs index 1abc480..2ad784f 100644 --- a/Source/EWSPDI/RecurrenceEnumerator.cs +++ b/Source/EWSPDI/RecurrenceEnumerator.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RecurrenceEnumerator.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/23/2018 -// Note : Copyright 2003-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a type-safe enumerator for Recurrence objects // @@ -33,8 +32,8 @@ public class RecurrenceEnumerator : IEnumerator // These are used to generate the recurrence dates and track progress through the sequence private int idx; - private DateTimeCollection dates; - private Recurrence recurrence; + private DateTimeCollection? dates; + private readonly Recurrence recurrence; private DateTime start, end; #endregion @@ -59,12 +58,12 @@ public RecurrenceEnumerator(Recurrence recurrence) /// /// Type-safe enumerator Current method /// - public DateTime Current => dates[idx]; + public DateTime Current => dates?[idx] ?? DateTime.MinValue; /// /// Type-unsafe IEnumerator.Current /// - object System.Collections.IEnumerator.Current => dates[idx]; + object IEnumerator.Current => dates?[idx] ?? DateTime.MinValue; /// /// Move to the next element diff --git a/Source/EWSPDI/SecondlyFrequency.cs b/Source/EWSPDI/SecondlyFrequency.cs index 639fd6e..795689d 100644 --- a/Source/EWSPDI/SecondlyFrequency.cs +++ b/Source/EWSPDI/SecondlyFrequency.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : SecondlyFrequency.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/22/2014 -// Note : Copyright 2003-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a class used to implements the Secondly frequency rules // @@ -36,10 +35,10 @@ internal sealed class SecondlyFrequency : IFrequencyRules /// The start date of the range limiting the instances generated /// The end date of the range limiting the instances generated /// The first instance date or null if there are no more instances - public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, + public RecurDateTime? FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, RecurDateTime to) { - RecurDateTime rdt = new RecurDateTime(start); + RecurDateTime rdt = new(start); int adjust; if(RecurDateTime.Compare(start, from, RecurDateTime.DateTimePart.Hour) < 0) @@ -56,7 +55,9 @@ public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime if(RecurDateTime.Compare(rdt, end, RecurDateTime.DateTimePart.Hour) > 0 || RecurDateTime.Compare(rdt, to, RecurDateTime.DateTimePart.Hour) > 0) + { return null; + } return rdt; } @@ -177,6 +178,7 @@ public int BySecond(Recurrence r, RecurDateTimeCollection dates) // Don't bother if either collection is empty if(count != 0 && r.BySecond.Count != 0) + { for(int idx = 0, nCollIdx = 0; idx < count; idx++) { // Remove the date/time if the second isn't wanted @@ -189,6 +191,7 @@ public int BySecond(Recurrence r, RecurDateTimeCollection dates) else nCollIdx++; } + } return dates.Count; } diff --git a/Source/EWSPDI/StringCollection.cs b/Source/EWSPDI/StringCollection.cs index 3cec462..f184bea 100644 --- a/Source/EWSPDI/StringCollection.cs +++ b/Source/EWSPDI/StringCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : StringCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/23/2018 -// Note : Copyright 2014-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2014-2025, Eric Woodruff, All rights reserved // // This file contains a type-safe collection class that is used to contain string objects // @@ -45,7 +44,7 @@ public class StringCollection : Collection /// This event is raised when an item is added or removed from the list, when the list is cleared, and /// when an item is replaced in the list. /// - public event ListChangedEventHandler ListChanged; + public event ListChangedEventHandler? ListChanged; /// /// This raises the event @@ -89,12 +88,13 @@ public StringCollection(IEnumerable values) public void AddRange(IEnumerable values) { if(values != null) + { try { suppressListChanged = true; foreach(string s in values) - base.Add(s); + this.Add(s); } finally { @@ -102,6 +102,7 @@ public void AddRange(IEnumerable values) OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } + } } /// @@ -111,7 +112,7 @@ public void AddRange(IEnumerable values) /// The number of items to remove public void RemoveRange(int index, int count) { - ((List)base.Items).RemoveRange(index, count); + ((List)this.Items).RemoveRange(index, count); OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } @@ -127,7 +128,7 @@ public void RemoveRange(int index, int count) /// Pass true for a case-insensitive sort or false for a case-sensitive sort public void Sort(bool ascending, bool ignoreCase) { - ((List)base.Items).Sort((x, y) => + ((List)this.Items).Sort((x, y) => { if(ascending) return String.Compare(x, y, ignoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture); diff --git a/Source/EWSPDI/UniqueIntegerCollection.cs b/Source/EWSPDI/UniqueIntegerCollection.cs index ff86e6e..6f8f21d 100644 --- a/Source/EWSPDI/UniqueIntegerCollection.cs +++ b/Source/EWSPDI/UniqueIntegerCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : UniqueIntegerCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/23/2018 -// Note : Copyright 2003-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a type-safe collection class that is used to contain a set of unique integer values with // an optional range restriction and zero exclusion. @@ -41,8 +40,8 @@ public class UniqueIntegerCollection : Collection //===================================================================== // These are used to parse a string of values for adding into the collection - private static Regex reStripNonDigits = new Regex(@"[^0-9\-,]"); - private static Regex reIsRange = new Regex("(?<=[^-])-"); + private static readonly Regex reStripNonDigits = new(@"[^0-9\-,]"); + private static readonly Regex reIsRange = new("(?<=[^-])-"); #endregion @@ -150,8 +149,10 @@ public UniqueIntegerCollection(UniqueIntegerCollection values) public void AddRange(IEnumerable values) { if(values != null) + { foreach(int v in values) - base.Add(v); + this.Add(v); + } } /// @@ -172,20 +173,22 @@ protected override void InsertItem(int index, int item) if(item == 0 && !this.AllowZero) throw new ArgumentException(LR.GetString("ExUICZerosNotAllowed"), nameof(item)); - int curIdx = base.IndexOf(item); + int curIdx = this.IndexOf(item); if(curIdx == -1) base.InsertItem(index, item); else + { if(index != curIdx) { - base.RemoveAt(curIdx); + this.RemoveAt(curIdx); - if(index > base.Count) - base.InsertItem(base.Count, item); + if(index > this.Count) + base.InsertItem(this.Count, item); else base.InsertItem(index, item); } + } } /// @@ -196,7 +199,7 @@ protected override void InsertItem(int index, int item) /// If the integer already exists in the collection, it will be moved to the new position protected override void SetItem(int index, int item) { - int curIdx = base.IndexOf(item); + int curIdx = this.IndexOf(item); if(curIdx == -1) base.SetItem(index, item); @@ -212,7 +215,7 @@ protected override void SetItem(int index, int item) /// The number of items to remove public void RemoveRange(int index, int count) { - ((List)base.Items).RemoveRange(index, count); + ((List)this.Items).RemoveRange(index, count); } /// @@ -221,7 +224,7 @@ public void RemoveRange(int index, int count) /// Pass true for ascending order, false for descending order public void Sort(bool ascending) { - ((List)base.Items).Sort((x, y) => + ((List)this.Items).Sort((x, y) => { if(ascending) return x.CompareTo(y); @@ -237,13 +240,13 @@ public void Sort(bool ascending) /// format. For example: 1,10,15-20,30-35,100 public override string ToString() { - StringBuilder sb = new StringBuilder(256); - int idx, value, startValue, count = base.Count; + StringBuilder sb = new(256); + int idx, value, startValue, count = this.Count; // Copy the items to an array and sort them in ascending order. We do this so as not to disturb the // order of the collection. - int[] array = new int[base.Count]; - base.CopyTo(array, 0); + int[] array = new int[this.Count]; + this.CopyTo(array, 0); Array.Sort(array); @@ -292,23 +295,29 @@ public override string ToString() /// ic.ParseValues("1, 10, 15-20, 30-35, 100") /// /// - public void ParseValues(string values) + public void ParseValues(string? values) { string[] parts, range; int value; + if(String.IsNullOrWhiteSpace(values)) + return; + // Remove all characters that are not a digit, dash, or comma string parse = reStripNonDigits.Replace(values, String.Empty); - parts = parse.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + parts = parse.Split([','], StringSplitOptions.RemoveEmptyEntries); foreach(string s in parts) + { if(!reIsRange.IsMatch(s)) { // Single value. Discard invalid and out of range entries. if(Int32.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out value) && value >= this.MinimumValue && value <= this.MaximumValue && (value != 0 || this.AllowZero)) - base.Add(value); + { + this.Add(value); + } } else { @@ -331,12 +340,13 @@ public void ParseValues(string values) while(low <= high) { if(low >= this.MinimumValue && low <= this.MaximumValue && (low != 0 || this.AllowZero)) - base.Add(low); + this.Add(low); low++; } } } + } } #endregion } diff --git a/Source/EWSPDI/WeeklyFrequency.cs b/Source/EWSPDI/WeeklyFrequency.cs index 4523fc3..1022eaf 100644 --- a/Source/EWSPDI/WeeklyFrequency.cs +++ b/Source/EWSPDI/WeeklyFrequency.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : WeeklyFrequency.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/22/2014 -// Note : Copyright 2003-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a class used to implements the Weekly frequency rules // @@ -36,10 +35,10 @@ internal sealed class WeeklyFrequency : IFrequencyRules /// The start date of the range limiting the instances generated /// The end date of the range limiting the instances generated /// The first instance date or null if there are no more instances - public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, + public RecurDateTime? FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, RecurDateTime to) { - RecurDateTime rdtWeek, rdt = new RecurDateTime(start); + RecurDateTime rdtWeek, rdt = new(start); int adjust; // Get the difference between the recurrence start and the limiting range start @@ -63,7 +62,9 @@ public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime if(RecurDateTime.Compare(rdtWeek, end, RecurDateTime.DateTimePart.Day) > 0 || RecurDateTime.Compare(rdtWeek, to, RecurDateTime.DateTimePart.Day) > 0) + { return null; + } return rdt; } @@ -89,7 +90,9 @@ public bool FindNext(Recurrence r, RecurDateTime end, RecurDateTime to, RecurDat if(RecurDateTime.Compare(rdtWeek, end, RecurDateTime.DateTimePart.Day) > 0 || RecurDateTime.Compare(rdtWeek, to, RecurDateTime.DateTimePart.Day) > 0) + { return false; + } return true; } diff --git a/Source/EWSPDI/YearlyFrequency.cs b/Source/EWSPDI/YearlyFrequency.cs index ae971d6..4eabf0f 100644 --- a/Source/EWSPDI/YearlyFrequency.cs +++ b/Source/EWSPDI/YearlyFrequency.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : YearlyFrequency.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/25/2020 -// Note : Copyright 2003-2020, Eric Woodruff, All rights reserved +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This file contains a class used to implements the Yearly frequency rules // @@ -35,12 +35,12 @@ internal sealed class YearlyFrequency : IFrequencyRules /// The start date of the range limiting the instances generated /// The end date of the range limiting the instances generated /// The first instance date or null if there are no more instances - public RecurDateTime FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, + public RecurDateTime? FindStart(Recurrence r, RecurDateTime start, RecurDateTime end, RecurDateTime from, RecurDateTime to) { int adjust; - RecurDateTime rdt = new RecurDateTime(start); + RecurDateTime rdt = new(start); // Adjust the year if the starting date is before the limiting range start date if(rdt.Year < from.Year) @@ -92,6 +92,7 @@ public int ByMonth(Recurrence r, RecurDateTimeCollection dates) // Don't bother if either collection is empty if(count != 0 && byMonth.Count != 0) + { for(int idx = 0; idx < count; idx++) { rdt = dates[0]; @@ -104,6 +105,7 @@ public int ByMonth(Recurrence r, RecurDateTimeCollection dates) dates.Add(rdtNew); } } + } return dates.Count; } @@ -126,6 +128,7 @@ public int ByWeekNo(Recurrence r, RecurDateTimeCollection dates) // Don't bother if either collection is empty if(count != 0 && byWeekNo.Count != 0) + { for(int idx = 0; idx < count; idx++) { rdt = dates[0]; @@ -157,6 +160,7 @@ public int ByWeekNo(Recurrence r, RecurDateTimeCollection dates) dates.Add(rdtNew); } } + } return dates.Count; } @@ -179,6 +183,7 @@ public int ByYearDay(Recurrence r, RecurDateTimeCollection dates) // Don't bother if either collection is empty if(count != 0 && byYearDay.Count != 0) + { for(int idx = 0; idx < count; idx++) { rdt = dates[0]; @@ -206,6 +211,7 @@ public int ByYearDay(Recurrence r, RecurDateTimeCollection dates) dates.Add(rdtNew); } } + } return dates.Count; } @@ -241,6 +247,7 @@ public int ByDay(Recurrence r, RecurDateTimeCollection dates) // Don't bother if either collection is empty if(count != 0 && byDay.Count != 0) + { for(int idx = 0; idx < count; idx++) { rdt = dates[0]; @@ -287,6 +294,7 @@ public int ByDay(Recurrence r, RecurDateTimeCollection dates) dates.Add(new RecurDateTime(rdtNew)); } } + } return dates.Count; } diff --git a/Source/EWSPDIData/Binding/ChildPropertyDescriptor.cs b/Source/EWSPDIData/Binding/ChildPropertyDescriptor.cs index 43616ab..c5fe4ad 100644 --- a/Source/EWSPDIData/Binding/ChildPropertyDescriptor.cs +++ b/Source/EWSPDIData/Binding/ChildPropertyDescriptor.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ChildPropertyDescriptor.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2007-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2007-2025, Eric Woodruff, All rights reserved // // This file contains a property descriptor that is used to return information for a child property // @@ -32,7 +31,8 @@ public class ChildPropertyDescriptor : PropertyDescriptor //===================================================================== // The parent and child property descriptors - private PropertyDescriptor parentPD, childPD; + private readonly PropertyDescriptor parentPD, childPD; + #endregion #region Properties diff --git a/Source/EWSPDIData/Binding/ChildPropertyTypeDescriptionProvider.cs b/Source/EWSPDIData/Binding/ChildPropertyTypeDescriptionProvider.cs index c8b9ca7..d033b63 100644 --- a/Source/EWSPDIData/Binding/ChildPropertyTypeDescriptionProvider.cs +++ b/Source/EWSPDIData/Binding/ChildPropertyTypeDescriptionProvider.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ChildPropertyTypeDescriptionProvider.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/05/2014 -// Note : Copyright 2007-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2007-2025, Eric Woodruff, All rights reserved // // This file contains a custom type description provider that associates the ChildPropertyTypeDescriptor with a // specific type of object. @@ -33,7 +32,7 @@ public class ChildPropertyTypeDescriptionProvider : TypeDescriptionProvider #region Private data members //===================================================================== - private ICustomTypeDescriptor customTD; + private ICustomTypeDescriptor customTD = null!; #endregion @@ -71,8 +70,7 @@ protected ChildPropertyTypeDescriptionProvider(Type objectType) : /// An that can provide metadata for the type public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { - if(customTD == null) - customTD = new ChildPropertyTypeDescriptor(base.GetTypeDescriptor(objectType, instance)); + customTD ??= new ChildPropertyTypeDescriptor(base.GetTypeDescriptor(objectType, instance)); return customTD; } diff --git a/Source/EWSPDIData/Binding/ChildPropertyTypeDescriptor.cs b/Source/EWSPDIData/Binding/ChildPropertyTypeDescriptor.cs index 3b5f94e..0e4bba8 100644 --- a/Source/EWSPDIData/Binding/ChildPropertyTypeDescriptor.cs +++ b/Source/EWSPDIData/Binding/ChildPropertyTypeDescriptor.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ChildPropertyTypeDescriptor.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/05/2014 -// Note : Copyright 2007-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2007-2025, Eric Woodruff, All rights reserved // // This file contains a custom type descriptor that is used to add child properties to the set of visible, // bindable properties for an object. @@ -79,7 +78,7 @@ public ChildPropertyTypeDescriptor(ICustomTypeDescriptor parent) : base(parent) /// To prevent endless recursion and stack overflows, it will only go down three levels. /// Properties with a set to false are ignored. Properties with a /// are not added to the collection but their children are added. - private void GetChildProperties(PropertyDescriptor parentProp, string baseName, Attribute[] filter, + private void GetChildProperties(PropertyDescriptor? parentProp, string baseName, Attribute[] filter, PropertyDescriptorCollection props, List newProps) { PropertyDescriptorCollection childProps, otherChildren; @@ -97,6 +96,7 @@ private void GetChildProperties(PropertyDescriptor parentProp, string baseName, nestingLevel++; foreach(PropertyDescriptor pd in props) + { if(!pd.PropertyType.IsPrimitive && pd.PropertyType != typeof(string)) { // If it's not browsable, ignore it. We shouldn't have to do this but the initial @@ -136,6 +136,7 @@ private void GetChildProperties(PropertyDescriptor parentProp, string baseName, this.GetChildProperties(parent, rootName, filter, otherChildren, newProps); } } + } } finally { @@ -155,7 +156,7 @@ public override PropertyDescriptorCollection GetProperties(Attribute[] attribute // This seems to ignore the filter so GetChildProperties() will get rid of all non-browsable // properties. PropertyDescriptorCollection props = base.GetProperties(attributes); - List newProps = new List(); + List newProps = []; this.GetChildProperties(null, String.Empty, attributes, props, newProps); @@ -171,11 +172,13 @@ public override PropertyDescriptorCollection GetProperties(Attribute[] attribute // Now we'll remove hidden top-level properties for(int idx = 0; idx < props.Count; idx++) + { if(props[idx].Attributes[typeof(HidePropertyAttribute)] != null) { props.RemoveAt(idx); idx--; } + } } return props; diff --git a/Source/EWSPDIData/Binding/ExtendedBindingList.cs b/Source/EWSPDIData/Binding/ExtendedBindingList.cs index a7a9dcd..babe198 100644 --- a/Source/EWSPDIData/Binding/ExtendedBindingList.cs +++ b/Source/EWSPDIData/Binding/ExtendedBindingList.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ExtendedBindingList.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2007-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2007-2025, Eric Woodruff, All rights reserved // // This file contains a generic, bindable base class used to hold a collection of items and supports various // useful features such as sorting and searching. @@ -40,7 +39,7 @@ public class ExtendedBindingList : BindingList where T : ICloneable private bool isSorted; // The property descriptor and direction for the current sort - private PropertyDescriptor sortProperty; + private PropertyDescriptor? sortProperty; private ListSortDirection sortDirection; #endregion @@ -81,8 +80,10 @@ public ExtendedBindingList(IList items) : base(items) public void AddRange(T[] items) { if(items != null) + { foreach(T item in items) - base.Add(item); + this.Add(item); + } } /// @@ -94,8 +95,10 @@ public void AddRange(T[] items) public ExtendedBindingList CloneRange(IEnumerable items) { if(items != null) + { foreach(T item in items) - base.Add((T)item.Clone()); + this.Add((T)item.Clone()); + } return this; } @@ -112,7 +115,7 @@ public ExtendedBindingList CloneRange(IEnumerable items) /// Returns true if at least one item matches the conditions or false if none of them do public bool Exists(Predicate match) { - return (((List)base.Items).FindIndex(0, base.Count, match) != -1); + return ((List)this.Items).FindIndex(0, this.Count, match) != -1; } /// @@ -123,7 +126,7 @@ public bool Exists(Predicate match) /// is found. public T Find(Predicate match) { - return ((List)base.Items).Find(match); + return ((List)this.Items).Find(match); } /// @@ -134,12 +137,9 @@ public T Find(Predicate match) /// conditions defined by the specified predicate. If none are found, the collection will be empty. public ExtendedBindingList FindAll(Predicate match) { - List foundItems = ((List)base.Items).FindAll(match); + List foundItems = ((List)this.Items).FindAll(match); - ExtendedBindingList collection = new ExtendedBindingList(); - - foreach(T item in foundItems) - collection.Add(item); + ExtendedBindingList collection = [.. foundItems]; return collection; } @@ -154,7 +154,7 @@ public ExtendedBindingList FindAll(Predicate match) /// There are three overloads for this method. public int FindIndex(Predicate match) { - return ((List)base.Items).FindIndex(0, base.Count, match); + return ((List)this.Items).FindIndex(0, this.Count, match); } /// @@ -167,7 +167,7 @@ public int FindIndex(Predicate match) /// defined by the predicate or -1 if nothing is found. public int FindIndex(int startIndex, Predicate match) { - return ((List)base.Items).FindIndex(startIndex, base.Count, match); + return ((List)this.Items).FindIndex(startIndex, this.Count, match); } /// @@ -181,7 +181,7 @@ public int FindIndex(int startIndex, Predicate match) /// defined by the predicate or -1 if nothing is found. public int FindIndex(int startIndex, int count, Predicate match) { - return ((List)base.Items).FindIndex(startIndex, count, match); + return ((List)this.Items).FindIndex(startIndex, count, match); } /// @@ -192,7 +192,7 @@ public int FindIndex(int startIndex, int count, Predicate match) /// is found. public T FindLast(Predicate match) { - return ((List)base.Items).FindLast(match); + return ((List)this.Items).FindLast(match); } /// @@ -205,7 +205,7 @@ public T FindLast(Predicate match) /// There are three overloads for this method public int FindLastIndex(Predicate match) { - return ((List)base.Items).FindLastIndex(0, base.Count, match); + return ((List)this.Items).FindLastIndex(0, this.Count, match); } /// @@ -219,7 +219,7 @@ public int FindLastIndex(Predicate match) /// defined by the predicate or -1 if nothing is found. public int FindLastIndex(int startIndex, Predicate match) { - return ((List)base.Items).FindLastIndex(startIndex, base.Count, match); + return ((List)this.Items).FindLastIndex(startIndex, this.Count, match); } /// @@ -234,7 +234,7 @@ public int FindLastIndex(int startIndex, Predicate match) /// defined by the predicate or -1 if nothing is found. public int FindLastIndex(int startIndex, int count, Predicate match) { - return ((List)base.Items).FindLastIndex(startIndex, count, match); + return ((List)this.Items).FindLastIndex(startIndex, count, match); } /// @@ -243,7 +243,7 @@ public int FindLastIndex(int startIndex, int count, Predicate match) /// The delegate to perform on each item in the collection public void ForEach(Action action) { - ((List)base.Items).ForEach(action); + ((List)this.Items).ForEach(action); } /// @@ -253,7 +253,7 @@ public void ForEach(Action action) /// Returns the number of items removed from the collection public int RemoveAll(Predicate match) { - int count = ((List)base.Items).RemoveAll(match); + int count = ((List)this.Items).RemoveAll(match); if(count != 0) base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); @@ -268,7 +268,7 @@ public int RemoveAll(Predicate match) /// The number of items to remove public void RemoveRange(int index, int count) { - ((List)base.Items).RemoveRange(index, count); + ((List)this.Items).RemoveRange(index, count); base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } @@ -279,7 +279,7 @@ public void RemoveRange(int index, int count) /// There are three overloads for this method public void Sort() { - ((List)base.Items).Sort(0, base.Count, null); + ((List)this.Items).Sort(0, this.Count, null); base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } @@ -291,7 +291,7 @@ public void Sort() /// null to use the default comparer. public void Sort(IComparer comparer) { - ((List)base.Items).Sort(comparer); + ((List)this.Items).Sort(comparer); base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } @@ -302,7 +302,7 @@ public void Sort(IComparer comparer) /// The delegate to use for the comparisons public void Sort(Comparison comparison) { - ((List)base.Items).Sort(comparison); + ((List)this.Items).Sort(comparison); base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } @@ -317,7 +317,7 @@ public void Sort(Comparison comparison) /// conditions. public bool TrueForAll(Predicate match) { - return ((List)base.Items).TrueForAll(match); + return ((List)this.Items).TrueForAll(match); } #endregion @@ -344,7 +344,7 @@ public bool TrueForAll(Predicate match) /// /// This returns the current property descriptor if sorting has been applied /// - protected override PropertyDescriptor SortPropertyCore => sortProperty; + protected override PropertyDescriptor? SortPropertyCore => sortProperty; /// /// This is overridden to apply a sort based on the selected property descriptor and sort direction @@ -353,8 +353,8 @@ public bool TrueForAll(Predicate match) /// The direction of the sort protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) { - PropertyComparer comparer = new PropertyComparer(prop, direction); - ((List)base.Items).Sort(comparer); + PropertyComparer comparer = new(prop, direction); + ((List)this.Items).Sort(comparer); sortProperty = prop; sortDirection = direction; @@ -393,31 +393,33 @@ protected override void RemoveSortCore() /// the specified value. protected override int FindCore(PropertyDescriptor prop, object key) { - return ((List)base.Items).FindIndex(0, base.Count, (x) => - { - int result; + return ((List)this.Items).FindIndex(0, this.Count, x => + { + int result; - object value = PropertyComparer.GetPropertyValue(x, prop.Name); + object? value = PropertyComparer.GetPropertyValue(x, prop.Name); - // Handle null values first - if(key == null && value == null) - return true; + // Handle null values first + if(key == null && value == null) + return true; - if((key == null && value != null) || (key != null && value == null)) - return false; + if((key == null && value != null) || (key != null && value == null)) + return false; - // Try comparing using IComparable. If that won't work, see if they are equal. If not, - // compare them as strings. - if(key is IComparable) - result = ((IComparable)key).CompareTo(value); + // Try comparing using IComparable. If that won't work, see if they are equal. If not, + // compare them as strings. + if(key is IComparable c) + result = c.CompareTo(value); + else + { + if(key!.Equals(value)) + result = 0; else - if(key.Equals(value)) - result = 0; - else - result = String.Compare(key.ToString(), value.ToString(), StringComparison.Ordinal); + result = String.Compare(key.ToString(), value!.ToString(), StringComparison.Ordinal); + } - return (result == 0); - }); + return result == 0; + }); } #endregion } diff --git a/Source/EWSPDIData/Binding/PropertyComparer.cs b/Source/EWSPDIData/Binding/PropertyComparer.cs index 2fd8201..146d68a 100644 --- a/Source/EWSPDIData/Binding/PropertyComparer.cs +++ b/Source/EWSPDIData/Binding/PropertyComparer.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : PropertyComparer.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2007-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2007-2025, Eric Woodruff, All rights reserved // // This file contains a generic comparer class that compares two items based on values retrieved from a property // descriptor. @@ -36,7 +35,7 @@ public class PropertyComparer : IComparer #region Private data members //===================================================================== - private PropertyDescriptor property; + private readonly PropertyDescriptor property; private readonly ListSortDirection direction; #endregion @@ -69,7 +68,7 @@ public PropertyComparer(PropertyDescriptor descriptor, ListSortDirection sortDir /// than zero when object X is greater than object Y. public int Compare(T x, T y) { - object value1, value2; + object? value1, value2; int result; // Get the value from the property in each object @@ -91,10 +90,10 @@ public int Compare(T x, T y) if(value1 is IComparable comp) result = comp.CompareTo(value2); else - if(value1.Equals(value2)) + if(value1!.Equals(value2)) result = 0; else - result = String.Compare(value1.ToString(), value2.ToString(), StringComparison.Ordinal); + result = String.Compare(value1.ToString(), value2!.ToString(), StringComparison.Ordinal); // Invert the result for descending order if(direction == ListSortDirection.Descending) @@ -115,17 +114,19 @@ public int Compare(T x, T y) /// The value of the property /// This takes into account child property references as well (those where the name contains an /// underscore). - public static object GetPropertyValue(T x, string propertyName) + public static object? GetPropertyValue(T x, string propertyName) { - Type t; - object value = x; + object? value = x; - string[] propNames = propertyName.Split('_'); - - foreach(string name in propNames) + if(value != null) { - t = value.GetType(); - value = t.GetProperty(name).GetValue(value, null); + string[] propNames = propertyName.Split('_'); + + foreach(string name in propNames) + { + Type t = value.GetType(); + value = t.GetProperty(name).GetValue(value, null); + } } return value; diff --git a/Source/EWSPDIData/DateTimeInstance.cs b/Source/EWSPDIData/DateTimeInstance.cs index 4ce5f45..c4c082d 100644 --- a/Source/EWSPDIData/DateTimeInstance.cs +++ b/Source/EWSPDIData/DateTimeInstance.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : DateTimeInstance.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the date/time instance class used by the time zone conversion methods // in the VCalendar class and the recurring instance generation methods of the RecurringObject class. @@ -32,23 +31,24 @@ namespace EWSoftware.PDI /// class. It is also used by the -derived classes to return a /// collection of recurring instances. /// - /// - /// - /// - /// - /// - /// + /// + /// + /// + /// + /// + /// public class DateTimeInstance { #region Private data members //===================================================================== - private static Regex reSplit = new Regex(@"\s+"); + private static readonly Regex reSplit = new(@"\s+"); private DateTime startDate, endDate; private Duration duration; private bool startIsDST, endIsDST; - private string startTZName, endTZName, timeZoneID; + private string? timeZoneID; + private string startTZName, endTZName; #endregion @@ -60,7 +60,7 @@ public class DateTimeInstance /// /// The value can be used to look up a object in a /// . If this is null, the times are assumed to be in local time. - public string TimeZoneId + public string? TimeZoneId { get => timeZoneID; set @@ -169,11 +169,13 @@ public string AbbreviatedStartTimeZoneName char[] letters = new char[parts.Length]; for(int idx = 0; idx < parts.Length; idx++) + { if(Char.IsLetter(parts[idx][0])) { letters[idx] = parts[idx][0]; count++; } + } return new String(letters, 0, count); } @@ -199,11 +201,13 @@ public string AbbreviatedEndTimeZoneName char[] letters = new char[parts.Length]; for(int idx = 0; idx < parts.Length; idx++) + { if(Char.IsLetter(parts[idx][0])) { letters[idx] = parts[idx][0]; count++; } + } return new String(letters, 0, count); } @@ -243,20 +247,22 @@ public DateTimeInstance(DateTime dt, Duration dur) /// /// Copy constructor /// - /// The date/time instance to copy - public DateTimeInstance(DateTimeInstance dti) + /// The date/time instance to copy + public DateTimeInstance(DateTimeInstance? dateTimeInstance) { - if(dti != null) + if(dateTimeInstance != null) { - timeZoneID = dti.TimeZoneId; - startDate = dti.StartDateTime; - endDate = dti.EndDateTime; - duration = dti.Duration; - startIsDST = dti.StartIsDaylightSavingTime; - endIsDST = dti.EndIsDaylightSavingTime; - startTZName = dti.StartTimeZoneName; - endTZName = dti.EndTimeZoneName; + timeZoneID = dateTimeInstance.TimeZoneId; + startDate = dateTimeInstance.StartDateTime; + endDate = dateTimeInstance.EndDateTime; + duration = dateTimeInstance.Duration; + startIsDST = dateTimeInstance.StartIsDaylightSavingTime; + endIsDST = dateTimeInstance.EndIsDaylightSavingTime; + startTZName = dateTimeInstance.StartTimeZoneName; + endTZName = dateTimeInstance.EndTimeZoneName; } + else + startTZName = endTZName = String.Empty; } #endregion @@ -270,12 +276,12 @@ public DateTimeInstance(DateTimeInstance dti) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is DateTimeInstance dti)) + if(obj is not DateTimeInstance dti) return false; - return (startDate == dti.StartDateTime && endDate == dti.EndDateTime && duration == dti.Duration && + return startDate == dti.StartDateTime && endDate == dti.EndDateTime && duration == dti.Duration && startIsDST == dti.StartIsDaylightSavingTime && endIsDST == dti.EndIsDaylightSavingTime && - startTZName == dti.StartTimeZoneName && endTZName == dti.EndTimeZoneName); + startTZName == dti.StartTimeZoneName && endTZName == dti.EndTimeZoneName; } /// @@ -293,7 +299,7 @@ public override int GetHashCode() /// A string containing the object information public override string ToString() { - StringBuilder sb = new StringBuilder(256); + StringBuilder sb = new(256); sb.AppendFormat("Start Date: {0} {1}\r\n", startDate, startTZName); sb.AppendFormat("End Date: {0} {1}\r\n", endDate, endTZName); @@ -337,7 +343,7 @@ public void ToLocalTime() /// This converts the date time instance information from its current time zone identified by /// the property to the specified time zone. The time zone ID property will be /// set to the specified time zone after conversion. - public void ToTimeZone(string tzid) + public void ToTimeZone(string? tzid) { DateTimeInstance dti, dtiEnd; @@ -348,8 +354,8 @@ public void ToTimeZone(string tzid) // Convert from local time? if(timeZoneID == null) { - dti = VCalendar.LocalTimeToTimeZoneTime(startDate, tzid); - dtiEnd = VCalendar.LocalTimeToTimeZoneTime(endDate, tzid); + dti = VCalendar.LocalTimeToTimeZoneTime(startDate, tzid!); + dtiEnd = VCalendar.LocalTimeToTimeZoneTime(endDate, tzid!); } else { diff --git a/Source/EWSPDIData/EWSoftware.PDI.Data.csproj b/Source/EWSPDIData/EWSoftware.PDI.Data.csproj index a22f5d1..0ea4a50 100644 --- a/Source/EWSPDIData/EWSoftware.PDI.Data.csproj +++ b/Source/EWSPDIData/EWSoftware.PDI.Data.csproj @@ -7,10 +7,10 @@ Eric Woodruff EWSoftware Personal Data Interchange Library EWSoftware PDI Data Library - Copyright (c) 2003-2023, Eric Woodruff, All Rights Reserved + Copyright (c) 2003-2025, Eric Woodruff, All Rights Reserved en - 2023.1.2.0 - 23.1.2.0 + 2025.1.9.0 + 25.1.9.0 This library contains classes used to create and consume vCard, vCalendar, and iCalendar files used to exchange contact and appointment information between applications such as Microsoft Outlook. See the project website for the code, a help file, and demos. Eric Woodruff https://raw.githubusercontent.com/EWSoftware/PDI/master/EWSPDI.png @@ -21,32 +21,28 @@ https://github.com/EWSoftware/PDI MS-PL Targets .NET Framework 4.0 and later and .NET Standard 2.0 and later - true + ReadMe.md False False False False + true ..\EWSPDI.snk true AllEnabledByDefault pdbonly true + latest + enable - - - - - + - - true - \ - + diff --git a/Source/EWSPDIData/EncodingUtils.cs b/Source/EWSPDIData/EncodingUtils.cs index 52c0c76..fd65a30 100644 --- a/Source/EWSPDIData/EncodingUtils.cs +++ b/Source/EWSPDIData/EncodingUtils.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : EncodeDecode.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/31/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a utility classes that helps with encoding and decoding values // @@ -39,7 +38,7 @@ public static class EncodingUtils /// of the encoded data to satisfy the requirements of some specifications such as vCard 2.1. If false, /// they are not appended. /// The Base 64 encoded string - public static string ToBase64(this string encode, int foldWidth, bool appendBlankLine) + public static string? ToBase64(this string? encode, int foldWidth, bool appendBlankLine) { // Don't bother if there is nothing to encode if(encode == null || encode.Length == 0) @@ -48,7 +47,7 @@ public static string ToBase64(this string encode, int foldWidth, bool appendBlan Encoding enc = Encoding.GetEncoding("iso-8859-1"); byte[] ba = enc.GetBytes(encode); - StringBuilder sb = new StringBuilder(Convert.ToBase64String(ba)); + StringBuilder sb = new(Convert.ToBase64String(ba)); // Insert line folds where necessary if requested. if(foldWidth > 0) @@ -69,7 +68,7 @@ public static string ToBase64(this string encode, int foldWidth, bool appendBlan /// /// The string to decode /// The decoded data as a string. This may or may not be a human-readable string. - public static string FromBase64(this string decode) + public static string? FromBase64(this string? decode) { // Don't bother if there is nothing to decode if(decode == null || decode.Length == 0) @@ -85,16 +84,16 @@ public static string FromBase64(this string decode) /// /// The string to escape /// The escaped string - public static string Escape(this string escapeText) + public static string? Escape(this string? escapeText) { // Don't bother if there is nothing to escape - if(escapeText == null || escapeText.Length == 0 || escapeText.IndexOfAny(new[] { - '\r', '\n', ',', ';', '\\'}) == -1) + if(escapeText == null || escapeText.Length == 0 || escapeText.IndexOfAny( + ['\r', '\n', ',', ';', '\\']) == -1) { return escapeText; } - StringBuilder sb = new StringBuilder(escapeText, escapeText.Length + 100); + StringBuilder sb = new(escapeText, escapeText.Length + 100); sb.Replace("\\", "\\\\"); sb.Replace(";", "\\;"); @@ -116,13 +115,13 @@ public static string Escape(this string escapeText) /// The escaped string /// This is mainly for vCard 2.1 properties in which commas and semi-colons should not be /// escaped. - public static string RestrictedEscape(this string escapeText) + public static string? RestrictedEscape(this string? escapeText) { // Don't bother if there is nothing to escape - if(escapeText == null || escapeText.Length == 0 || escapeText.IndexOfAny(new[] { '\r', '\n', '\\'}) == -1) + if(escapeText == null || escapeText.Length == 0 || escapeText.IndexOfAny(['\r', '\n', '\\']) == -1) return escapeText; - StringBuilder sb = new StringBuilder(escapeText, escapeText.Length + 100); + StringBuilder sb = new(escapeText, escapeText.Length + 100); sb.Replace("\\", "\\\\"); @@ -144,13 +143,13 @@ public static string RestrictedEscape(this string escapeText) /// unescaped. The specifications do not state that they have to be escaped, but some implementations /// do, so they are handled here too just in case. However, they will not be escaped when written back /// out. - public static string Unescape(this string unescapeText) + public static string? Unescape(this string? unescapeText) { // Don't bother if there is nothing to escape if(unescapeText == null || unescapeText.Length == 0 || unescapeText.IndexOf('\\') == -1) return unescapeText; - StringBuilder sb = new StringBuilder(unescapeText, unescapeText.Length + 100); + StringBuilder sb = new(unescapeText, unescapeText.Length + 100); sb.Replace("\\r\\n", "\r\n"); sb.Replace("\\R\\N", "\r\n"); @@ -180,13 +179,13 @@ public static string Unescape(this string unescapeText) /// The Quoted-Printable encoded string /// Character values 9, 32-60, and 62-126 go through as-is. All others are encoded as "=XX" /// where XX is the 2 digit hex value of the character (i.e. =0D=0A for a carriage return and line feed). - public static string ToQuotedPrintable(this string encode, int foldWidth) + public static string? ToQuotedPrintable(this string? encode, int foldWidth) { // Don't bother if there's nothing to encode if(encode == null || encode.Length == 0) return encode; - StringBuilder sb = new StringBuilder(encode.Length + 100); + StringBuilder sb = new(encode.Length + 100); foldWidth--; // Account for soft line break character @@ -227,13 +226,13 @@ public static string ToQuotedPrintable(this string encode, int foldWidth) /// /// The string to decode /// The decoded data as a string - public static string FromQuotedPrintable(this string decode) + public static string? FromQuotedPrintable(this string? decode) { // Don't bother if there's nothing to decode if(decode == null || decode.Length == 0 || decode.IndexOf('=') == -1) return decode; - StringBuilder sb = new StringBuilder(decode.Length); + StringBuilder sb = new(decode.Length); string hexDigits = "0123456789ABCDEF"; int pos1, pos2; diff --git a/Source/EWSPDIData/GlobalSuppressions.cs b/Source/EWSPDIData/GlobalSuppressions.cs index b938004d32135954c1c486ff87fd81ed4f6917d2..6f6e0bf5910a4273e7c56475087e737ee24160a1 100644 GIT binary patch delta 3137 zcmZ`+e@v8h80S$uk&7AXB za^tam8KIGx(dF2iN4!RiE{8_uoRj9vId(Z~P7QCXOdVr=f4sl$R{y=v=lML(_xbsK z-?wXW&dKRy`O@rpZzsK#v^i;8(kA?M_Ubt+ljbL-;_7)h=$dWANT!QKwn8>;Paf3( z9GM%#Zi}qR;gPw=K@+I*3JDZK8u2&78HR>EIoZ%v?7)ZCLX|au70)+fup|Rd+R9Yy z8rtnWCcTr&)#!heg;`Fg32(%JEa8o(%1xNYEx_@o&0K*;2huP(jpN~1elC!x4J6FV z^fC|ONajv0cr~n48-}ul(v$Na$~>uxpY6$EF;`=Be@d5gl^#xTNeFK)Y&OYVc>USk zCOL$&a<`l0F0|ww*5q(-$pRh_jrD|hh-791Mi-}(Kt7~kw%c6Bv&@cC3xHQ0rA#Y^ zmQ`|;6`tBHz`%z#-0R?Gyc;OJupyoi>Rx~;FA7F1KM%-c4LGrXnNJPN74BKNNR6h` z0(j4AMMtrlI|neq9slM4^HkDe8Sg^dh*CcJ)EMYP_*tP&{v{+(>6KU~JQIeo(Z@uX#r1$MPC{QOhWYzy zjf|uFO@{{$#%b)h?t>OH)sDHH{9*`4I?If4C4IS&hAmxUUL$OPW5_p_@~9B_u$X&c z0%`Jq9mh(<7;|-~yHr=Br^jS?`6KQ6D#a7MGn^GWx{IHTv7;fBhaBksv;yr)D!J20 z3&1W_p-92UpGYQ|5d#TwIodztL7SYFW8cX{%!>v6hHvi|W4fQ@FZm_R?FUaqbi8F? zSbaW)l02&8SHChi@{k{=!b^3XJk*hx#A&7s%ZfVB{%;zM+(*CFk0z}(;K!gX4ecKn zpnX)2KT(m2x4v^}2PP^l82a9b=I685Ing~aK&F#nhk6BdXka*W-ot}Y{L6suM9`Lw zwLc!w)%PxlK84*Al-Kdo9i|b&w##DU-4j)S+pmZbb59J5iQ?#itF0=ZQhKflzVDYY z6J_wm4n|QVC(wJiFDl{CByX^e^d{)f-<*m=Tv+zoEruXV^4@dMit^nCGPM*IC88q? zpwZJr`|e)kUizM7Y5V_?@b({k4+%x&aMAr)qAZ5~%>CWWg6U6V(VsERIZi*=gZ+Q= z1!N&mS=Wi0`ycJo$+sR~(4Rxo$Jnz%J<`|4@QmIS5-Wj5^x4zDmVsV*YHo@=3w*lt zIc=vdkcSqS)Obu7CWqz$Ur1gRYRRV5PF6et4LYyK3O972%?7u1q1q19Okkn)8K+P; z?LwBos#A?Km+>qVBxd}#OybMlg#d83;;{{hDg<{9`%F(3S=uK@U zGnG&lR}_}7uHyU0i$kK7ATC68(-pN>N+_oU&TTj32sr zW#XU=;$H~Dc_gz;aW{Z?8*1P44#m<4^u@>4FOpfR^lnlog%b{Kfn&<}W^E(sKY&7^ Nh(>oQ^pBtl{sln6cAfwL delta 3416 zcmZ`+eN0nV6wjR%@dZg+D^}LkQUM7xclC__r3do{m1WjKJGcc zd+vGV^r)t3aBAnZDR6p*5$;UMK{g0-S+GrWi$RWQVW^1cR2ZLQ+DW89a7?=nuGAQa z=DH--7v%O32VYxq0s_lfBY0*kmt*?D6a6hgZOOktZgW0ZezbwjY$X}Qu#j%^1gCsB zK9e|s9C|bfjC#rjxqcW-@j&_sJygcLsX8Gni5f zMG+=wT~xxbp6F!gjK|D^NT^Js%>D<;LRY$Ew8sHqNt^}&asiKBg zsfsOGLu(LQv8{`QD{Eh8+p(=v#kUkI@%Tmr+Yx`CJ69jaqoJfp$nJT8aoqADbD4;>vd`>2Q44CaSxb-MX1( z&)bR*tKUKk6yehf#VS{ow>1to_--L-Omwtwr+U?GmmQs+d5FAK_Rd7Qc4sMxcX}2e z(7eBrg*&R~xuW%t-4(KRC+$X@{lGI5+^bfGT9iH!a%<8_fZ)Zury?^n?qNB6Lwf0H z4%Utf*Yo1@%-lPk$4@k$O&dx;v2bUf%FR7u1^a$N;a9vG&hH$-#TpJkscqikCv-TTnicmZxTb&=EpDm>gL zAJhYZBi#(j-~$Y5KSq$x+l=2_-+jCzI9i0ac|ASO+nkLc|AgEsZqC+no=Md5X|Ief zfT4|)<8z*R8-eXqqGZJIW17-=>MaCIPiM$sJ&^SIE#h}*C`;IBWXt zVTHPmeqT*{F3ICBi${3Uwb=$3K6jLa*LA$|0{Qci*NK4h{wc$+X#t|8;k+KWujs_d z)DK;B%Mfa>9FNnLc6(ST)Rz!LW%gf32UPCvIVa6*G|UsU5illWCkd? zI6Nue^d0HSpQk}-xU9@rGzLX>P;(O%9GD$VitHMe`?^QCRqOOJ4G(;W&V&fMu za&3*2QDiO+Jdu#kc>@pQ==XFRId6PPg%vN)0UU&N+W)ygsQT#&lXdK73xj&Ex*?=9 zLg+TpLp*u(c{yfd$af)$A5KG+455V$gLKLU9xkHakE^8GLqq*+V^MbpnFFKlc7yx3 zeBwIr5DV3Je+O|Gco>B6?_@A>B|)fvaGwcI{%e#$QtdI|DT}48yX3q*ObNb~;aV2% zdtAssW_5^aHvZj64sqVN2t)rol@OV%z%x5vIUA|RD)6k6sVn8*a|}8>#-h>ZbS2>?|`EU}d z;6qbTB)B{17%OJ{%ZTG+w5UYYJ6Y`~CnK$V!%X_7$P85p`+jJGGbWQJN+{$u%|V|{ zaPKpr#L3;Ug_eQ^S%~;_3v#Fxl*ltuQb|VPk$ DEIAAR diff --git a/Source/EWSPDIData/LocalizedResources.cs b/Source/EWSPDIData/LocalizedResources.cs index 7d1ca5f..02395d1 100644 --- a/Source/EWSPDIData/LocalizedResources.cs +++ b/Source/EWSPDIData/LocalizedResources.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : LocalizedResources.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains some internal classes used to manage the localized resources for the assembly // @@ -38,10 +37,10 @@ internal static class LR private const string ResourcesKey = "PDIData"; // The resource manager - private static ResourceManager rm; + private static ResourceManager rm = null!; // This is a helper object used to quickly lock the class when creating the resource manager - private static readonly object syncRoot = new Object(); + private static readonly object syncRoot = new(); #endregion @@ -84,12 +83,7 @@ private static ResourceManager Resources /// "[?:<key>]" if not found. internal static string GetString(string name) { - string s = Resources.GetString(name, null); - - if(s == null) - s = $"[?:{name}]"; - - return s; + return Resources.GetString(name, null) ?? $"[?:{name}]"; } /// @@ -99,7 +93,7 @@ internal static string GetString(string name) /// The arguments to be formatted into the retrieved string /// Returns the value of the string resource formatted with the passed arguments if found or the /// key name enclosed in "[?:<key>]" if not found. - internal static string GetString(string name, params object[] args) + internal static string GetString(string name, params object?[] args) { return String.Format(CultureInfo.CurrentCulture, GetString(name), args); } diff --git a/Source/EWSPDIData/PDIObjects/CalendarObject.cs b/Source/EWSPDIData/PDIObjects/CalendarObject.cs index c421ba0..25d27d4 100644 --- a/Source/EWSPDIData/PDIObjects/CalendarObject.cs +++ b/Source/EWSPDIData/PDIObjects/CalendarObject.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : CalendarObject.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the base class for all calendar related Personal Data Interchange (PDI) classes and the // interface that it implements. @@ -78,7 +77,7 @@ public override SpecificationVersions Version /// /// The old ID being replaced /// The new ID to use - public abstract void UpdateTimeZoneId(string oldId, string newId); + public abstract void UpdateTimeZoneId(string? oldId, string? newId); /// /// This is used to apply the selected time zone to all date/time objects in the component and convert @@ -87,7 +86,7 @@ public override SpecificationVersions Version /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public abstract void ApplyTimeZone(VTimeZone vTimeZone); + public abstract void ApplyTimeZone(VTimeZone? vTimeZone); /// /// This is used to set the selected time zone in all date/time objects in the component without @@ -96,7 +95,7 @@ public override SpecificationVersions Version /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public abstract void SetTimeZone(VTimeZone vTimeZone); + public abstract void SetTimeZone(VTimeZone? vTimeZone); /// /// This helper method can be used to add a time zone ID to the string collection when one is used on the @@ -111,7 +110,7 @@ protected static void AddTimeZoneIfUsed(BaseDateTimeProperty dateProp, StringCol { if(dateProp != null && dateProp.TimeZoneDateTime != DateTime.MinValue) { - string tzId = dateProp.TimeZoneId; + string? tzId = dateProp.TimeZoneId; if(tzId != null && !timeZoneIds.Contains(tzId)) timeZoneIds.Add(tzId); @@ -125,7 +124,7 @@ protected static void AddTimeZoneIfUsed(BaseDateTimeProperty dateProp, StringCol /// The old ID being replaced /// The new ID to use /// If the property's current time zone ID matches the old ID, it is replaced with the new ID - protected static void UpdatePropertyTimeZoneId(BaseDateTimeProperty dateProp, string oldId, string newId) + protected static void UpdatePropertyTimeZoneId(BaseDateTimeProperty dateProp, string? oldId, string? newId) { if(dateProp != null && dateProp.TimeZoneId == oldId) dateProp.TimeZoneId = newId; @@ -138,7 +137,7 @@ protected static void UpdatePropertyTimeZoneId(BaseDateTimeProperty dateProp, st /// The new time zone component to use /// If the property's current time zone ID does not match the one in the new time zone, it is /// updated with the new ID and the date/time is adjusted to the new time zone. - protected static void ApplyPropertyTimeZone(BaseDateTimeProperty dateProp, VTimeZone vTimeZone) + protected static void ApplyPropertyTimeZone(BaseDateTimeProperty dateProp, VTimeZone? vTimeZone) { if(dateProp != null && (vTimeZone == null || dateProp.TimeZoneId != vTimeZone.TimeZoneId.Value)) { @@ -165,7 +164,7 @@ protected static void ApplyPropertyTimeZone(BaseDateTimeProperty dateProp, VTime /// The new time zone component to use /// If the property's current time zone ID does not match the one in the new time zone, it is /// updated with the new ID. The date/time value is not changed. - protected static void SetPropertyTimeZone(BaseDateTimeProperty dateProp, VTimeZone vTimeZone) + protected static void SetPropertyTimeZone(BaseDateTimeProperty dateProp, VTimeZone? vTimeZone) { if(dateProp != null && (vTimeZone == null || dateProp.TimeZoneId != vTimeZone.TimeZoneId.Value)) { @@ -183,11 +182,11 @@ protected static void SetPropertyTimeZone(BaseDateTimeProperty dateProp, VTimeZo /// Returns a text description of the object suitable for saving to a PDI data stream public override string ToString() { - using(var sw = new StringWriter(new StringBuilder(1024), CultureInfo.InvariantCulture)) - { - this.WriteToStream(sw, null); - return sw.ToString(); - } + using var sw = new StringWriter(new StringBuilder(1024), CultureInfo.InvariantCulture); + + this.WriteToStream(sw, null); + + return sw.ToString(); } /// @@ -215,7 +214,7 @@ public void WriteToStream(TextWriter tw) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they convert /// themselves to a string or write themselves to a PDI data stream. - public abstract void WriteToStream(TextWriter tw, StringBuilder sb); + public abstract void WriteToStream(TextWriter tw, StringBuilder? sb); #endregion } diff --git a/Source/EWSPDIData/PDIObjects/ObservanceRule.cs b/Source/EWSPDIData/PDIObjects/ObservanceRule.cs index 1a6643e..ac621b9 100644 --- a/Source/EWSPDIData/PDIObjects/ObservanceRule.cs +++ b/Source/EWSPDIData/PDIObjects/ObservanceRule.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ObservanceRule.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the Observance Rule object used by iCalendar STANDARD and DAYLIGHT // objects. @@ -38,22 +37,20 @@ public class ObservanceRule : CalendarObject #region Private data members //===================================================================== - private ObservanceRuleType ruleType; - // Single properties - private StartDateProperty startDate; - private TimeZoneOffsetProperty offsetFrom; - private TimeZoneOffsetProperty offsetTo; - private CommentProperty comment; + private StartDateProperty startDate = null!; + private TimeZoneOffsetProperty offsetFrom = null!; + private TimeZoneOffsetProperty offsetTo = null!; + private CommentProperty comment = null!; // Observance property collections. There can be one or more of each of these properties so they are // stored in a collection. - private RRulePropertyCollection rRules; - private RDatePropertyCollection rDates; - private TimeZoneNamePropertyCollection tzNames; + private RRulePropertyCollection rRules = null!; + private RDatePropertyCollection rDates = null!; + private TimeZoneNamePropertyCollection tzNames = null!; // This is a catch-all that holds all unknown or extension properties - private CustomPropertyCollection customProps; + private CustomPropertyCollection customProps = null!; #endregion @@ -69,11 +66,7 @@ public class ObservanceRule : CalendarObject /// /// This is used to set or get the rule type /// - public ObservanceRuleType RuleType - { - get => ruleType; - set => ruleType = value; - } + public ObservanceRuleType RuleType { get; set; } /// /// This is used to get the start date/time (DTSTART) property @@ -83,8 +76,7 @@ public StartDateProperty StartDateTime { get { - if(startDate == null) - startDate = new StartDateProperty(); + startDate ??= new StartDateProperty(); return startDate; } @@ -98,8 +90,7 @@ public TimeZoneOffsetProperty OffsetFrom { get { - if(offsetFrom == null) - offsetFrom = new TimeZoneOffsetProperty(true); + offsetFrom ??= new TimeZoneOffsetProperty(true); return offsetFrom; } @@ -115,8 +106,7 @@ public TimeZoneOffsetProperty OffsetTo { get { - if(offsetTo == null) - offsetTo = new TimeZoneOffsetProperty(false); + offsetTo ??= new TimeZoneOffsetProperty(false); return offsetTo; } @@ -130,8 +120,7 @@ public CommentProperty Comment { get { - if(comment == null) - comment = new CommentProperty(); + comment ??= new CommentProperty(); return comment; } @@ -145,8 +134,7 @@ public RRulePropertyCollection RecurrenceRules { get { - if(rRules == null) - rRules = new RRulePropertyCollection(); + rRules ??= []; return rRules; } @@ -161,8 +149,7 @@ public RDatePropertyCollection RecurDates { get { - if(rDates == null) - rDates = new RDatePropertyCollection(); + rDates ??= []; return rDates; } @@ -176,8 +163,7 @@ public TimeZoneNamePropertyCollection TimeZoneNames { get { - if(tzNames == null) - tzNames = new TimeZoneNamePropertyCollection(); + tzNames ??= []; return tzNames; } @@ -192,8 +178,7 @@ public CustomPropertyCollection CustomProperties { get { - if(customProps == null) - customProps = new CustomPropertyCollection(); + customProps ??= []; return customProps; } @@ -218,7 +203,7 @@ public ObservanceRule() : this(ObservanceRuleType.Standard) public ObservanceRule(ObservanceRuleType type) { this.Version = SpecificationVersions.iCalendar20; - ruleType = type; + this.RuleType = type; } #endregion @@ -231,7 +216,7 @@ public ObservanceRule(ObservanceRuleType type) /// A clone of the object. public override object Clone() { - ObservanceRule o = new ObservanceRule(); + ObservanceRule o = new(); o.Clone(this); return o; } @@ -246,7 +231,8 @@ protected override void Clone(PDIObject p) this.ClearProperties(); - ruleType = o.RuleType; + this.RuleType = o.RuleType; + startDate = (StartDateProperty)o.StartDateTime.Clone(); offsetFrom = (TimeZoneOffsetProperty)o.OffsetFrom.Clone(); offsetTo = (TimeZoneOffsetProperty)o.OffsetTo.Clone(); @@ -264,16 +250,16 @@ protected override void Clone(PDIObject p) /// public override void ClearProperties() { - startDate = null; - offsetFrom = null; - offsetTo = null; - comment = null; + startDate = null!; + offsetFrom = null!; + offsetTo = null!; + comment = null!; - rRules = null; - rDates = null; - tzNames = null; + rRules = null!; + rDates = null!; + tzNames = null!; - customProps = null; + customProps = null!; } /// @@ -293,17 +279,10 @@ public override void PropagateVersion() if(comment != null) comment.Version = this.Version; - if(rRules != null) - rRules.PropagateVersion(this.Version); - - if(rDates != null) - rDates.PropagateVersion(this.Version); - - if(tzNames != null) - tzNames.PropagateVersion(this.Version); - - if(customProps != null) - customProps.PropagateVersion(this.Version); + rRules?.PropagateVersion(this.Version); + rDates?.PropagateVersion(this.Version); + tzNames?.PropagateVersion(this.Version); + customProps?.PropagateVersion(this.Version); } /// @@ -320,7 +299,7 @@ public override void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public override void UpdateTimeZoneId(string oldId, string newId) + public override void UpdateTimeZoneId(string? oldId, string? newId) { } @@ -329,7 +308,7 @@ public override void UpdateTimeZoneId(string oldId, string newId) /// /// A object that will be used for all date/time objects /// in the component. - public override void ApplyTimeZone(VTimeZone vTimeZone) + public override void ApplyTimeZone(VTimeZone? vTimeZone) { } @@ -338,7 +317,7 @@ public override void ApplyTimeZone(VTimeZone vTimeZone) /// /// A object that will be used for all date/time objects /// in the component. - public override void SetTimeZone(VTimeZone vTimeZone) + public override void SetTimeZone(VTimeZone? vTimeZone) { } @@ -351,11 +330,11 @@ public override void SetTimeZone(VTimeZone vTimeZone) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream. - public override void WriteToStream(TextWriter tw, StringBuilder sb) + public override void WriteToStream(TextWriter tw, StringBuilder? sb) { PropagateVersion(); - if(ruleType == ObservanceRuleType.Standard) + if(this.RuleType == ObservanceRuleType.Standard) tw.Write("BEGIN:STANDARD\r\n"); else tw.Write("BEGIN:DAYLIGHT\r\n"); @@ -376,6 +355,7 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(r, sb, tw); if(rDates != null && rDates.Count != 0) + { foreach(RDateProperty rdt in rDates) { rdt.TimeZoneId = null; // Never use a time zone ID @@ -387,16 +367,21 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(rdt, sb, tw); } + } if(tzNames != null && tzNames.Count != 0) + { foreach(TimeZoneNameProperty tzn in tzNames) BaseProperty.WriteToStream(tzn, sb, tw); + } if(customProps != null && customProps.Count != 0) + { foreach(CustomProperty c in customProps) BaseProperty.WriteToStream(c, sb, tw); + } - if(ruleType == ObservanceRuleType.Standard) + if(this.RuleType == ObservanceRuleType.Standard) tw.Write("END:STANDARD\r\n"); else tw.Write("END:DAYLIGHT\r\n"); @@ -409,12 +394,12 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is ObservanceRule obr)) + if(obj is not ObservanceRule obr) return false; // The ToString() method returns a text representation of the observance based on all of its settings // so it's a reliable way to tell if two instances are the same. - return (this == obr || this.ToString() == obr.ToString()); + return this == obr || this.ToString() == obr.ToString(); } /// diff --git a/Source/EWSPDIData/PDIObjects/ObservanceRuleCollection.cs b/Source/EWSPDIData/PDIObjects/ObservanceRuleCollection.cs index dc27e60..fbda992 100644 --- a/Source/EWSPDIData/PDIObjects/ObservanceRuleCollection.cs +++ b/Source/EWSPDIData/PDIObjects/ObservanceRuleCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ObservanceRuleCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/06/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for ObservanceRule objects // @@ -63,8 +62,8 @@ public ObservanceRuleCollection(IList rules) : base(rules) /// Returns the new rule that was created and added to the collection public ObservanceRule Add(ObservanceRuleType ruleType) { - ObservanceRule rule = new ObservanceRule(ruleType); - base.Add(rule); + ObservanceRule rule = new(ruleType); + this.Add(rule); return rule; } @@ -75,7 +74,7 @@ public ObservanceRule Add(ObservanceRuleType ruleType) /// Pass true for ascending order, false for descending order public void Sort(bool ascending) { - ((List)base.Items).Sort((x, y) => + ((List)this.Items).Sort((x, y) => { int result; @@ -85,16 +84,20 @@ public void Sort(bool ascending) result = (int)x.RuleType - (int)y.RuleType; if(result == 0) + { result = (x.StartDateTime.DateTimeValue == y.StartDateTime.DateTimeValue) ? 0 : (x.StartDateTime.DateTimeValue < y.StartDateTime.DateTimeValue) ? -1 : 1; + } } else { result = (int)y.RuleType - (int)x.RuleType; if(result == 0) + { result = (y.StartDateTime.DateTimeValue == x.StartDateTime.DateTimeValue) ? 0 : (y.StartDateTime.DateTimeValue < x.StartDateTime.DateTimeValue) ? -1 : 1; + } } return result; diff --git a/Source/EWSPDIData/PDIObjects/RecurringObject.cs b/Source/EWSPDIData/PDIObjects/RecurringObject.cs index adca469..a501465 100644 --- a/Source/EWSPDIData/PDIObjects/RecurringObject.cs +++ b/Source/EWSPDIData/PDIObjects/RecurringObject.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RecurringObject.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains an abstract base class from which recurring calendar objects are derived. It defines a // common set of properties and methods used to resolve an object to one or more dates based on the combination @@ -23,6 +22,7 @@ using System; using System.IO; +using System.Linq; using System.Text; using EWSoftware.PDI.Properties; @@ -39,9 +39,9 @@ public abstract class RecurringObject : CalendarObject #region Private data members //===================================================================== - private RRulePropertyCollection rRules, exRules; - private RDatePropertyCollection rDates; - private ExDatePropertyCollection exDates; + private RRulePropertyCollection rRules = null!, exRules = null!; + private RDatePropertyCollection rDates = null!; + private ExDatePropertyCollection exDates = null!; #endregion @@ -71,8 +71,7 @@ public RRulePropertyCollection RecurrenceRules { get { - if(rRules == null) - rRules = new RRulePropertyCollection(); + rRules ??= []; return rRules; } @@ -86,8 +85,7 @@ public RRulePropertyCollection ExceptionRules { get { - if(exRules == null) - exRules = new RRulePropertyCollection(); + exRules ??= []; return exRules; } @@ -101,8 +99,7 @@ public RDatePropertyCollection RecurDates { get { - if(rDates == null) - rDates = new RDatePropertyCollection(); + rDates ??= []; return rDates; } @@ -116,8 +113,7 @@ public ExDatePropertyCollection ExceptionDates { get { - if(exDates == null) - exDates = new ExDatePropertyCollection(); + exDates ??= []; return exDates; } @@ -128,8 +124,8 @@ public ExDatePropertyCollection ExceptionDates /// /// It returns true if any recurrence rules, exception rules, recurrence dates, or exception dates /// are defined. It returns false if none of those items have been specified. - public bool IsRecurring => (this.RecurrenceRules.Count != 0 || this.ExceptionRules.Count != 0 || - this.RecurDates.Count != 0 || this.ExceptionDates.Count != 0); + public bool IsRecurring => this.RecurrenceRules.Count != 0 || this.ExceptionRules.Count != 0 || + this.RecurDates.Count != 0 || this.ExceptionDates.Count != 0; /// /// This must be implemented to return the start date/time property that is used to determine when the @@ -151,7 +147,7 @@ public abstract Duration InstanceDuration /// /// This must be implemented to return the time zone ID for the start date /// - public abstract string TimeZoneId + public abstract string? TimeZoneId { get; } @@ -204,10 +200,12 @@ public override void PropagateVersion() /// unique time zone IDs used by the calendar objects. public override void TimeZonesUsed(StringCollection timeZoneIds) { - string timeZoneId; + string? timeZoneId; if(rDates != null) + { foreach(RDateProperty rdt in rDates) + { if(rdt.ValueLocation == ValLocValue.DateTime && rdt.TimeZoneDateTime != DateTime.MinValue) { timeZoneId = rdt.TimeZoneId; @@ -215,10 +213,14 @@ public override void TimeZonesUsed(StringCollection timeZoneIds) if(timeZoneId != null && !timeZoneIds.Contains(timeZoneId)) timeZoneIds.Add(timeZoneId); } + } + } if(exDates != null) + { foreach(ExDateProperty edt in exDates) - CalendarObject.AddTimeZoneIfUsed(edt, timeZoneIds); + AddTimeZoneIfUsed(edt, timeZoneIds); + } } /// @@ -227,16 +229,22 @@ public override void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public override void UpdateTimeZoneId(string oldId, string newId) + public override void UpdateTimeZoneId(string? oldId, string? newId) { if(rDates != null) + { foreach(RDateProperty rdt in rDates) + { if(rdt.TimeZoneId == oldId) rdt.TimeZoneId = newId; + } + } if(exDates != null) + { foreach(ExDateProperty edt in exDates) - CalendarObject.UpdatePropertyTimeZoneId(edt, oldId, newId); + UpdatePropertyTimeZoneId(edt, oldId, newId); + } } /// @@ -246,10 +254,12 @@ public override void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public override void ApplyTimeZone(VTimeZone vTimeZone) + public override void ApplyTimeZone(VTimeZone? vTimeZone) { if(rDates != null) + { foreach(RDateProperty rdt in rDates) + { if(vTimeZone == null || rdt.TimeZoneId != vTimeZone.TimeZoneId.Value) { // If the time zone is null, just clear the time zone ID @@ -264,10 +274,14 @@ public override void ApplyTimeZone(VTimeZone vTimeZone) rdt.TimeZoneId = vTimeZone.TimeZoneId.Value; } } + } + } if(exDates != null) + { foreach(ExDateProperty edt in exDates) - CalendarObject.ApplyPropertyTimeZone(edt, vTimeZone); + ApplyPropertyTimeZone(edt, vTimeZone); + } } /// @@ -277,10 +291,12 @@ public override void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public override void SetTimeZone(VTimeZone vTimeZone) + public override void SetTimeZone(VTimeZone? vTimeZone) { if(rDates != null) + { foreach(RDateProperty rdt in rDates) + { if(vTimeZone == null || rdt.TimeZoneId != vTimeZone.TimeZoneId.Value) { // If the time zone is null, just clear the time zone ID @@ -289,10 +305,14 @@ public override void SetTimeZone(VTimeZone vTimeZone) else rdt.TimeZoneId = vTimeZone.TimeZoneId.Value; } + } + } if(exDates != null) + { foreach(ExDateProperty edt in exDates) - CalendarObject.SetPropertyTimeZone(edt, vTimeZone); + SetPropertyTimeZone(edt, vTimeZone); + } } /// @@ -303,23 +323,31 @@ public override void SetTimeZone(VTimeZone vTimeZone) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream. - public override void WriteToStream(TextWriter tw, StringBuilder sb) + public override void WriteToStream(TextWriter tw, StringBuilder? sb) { if(rRules != null && rRules.Count != 0) + { foreach(RRuleProperty r in rRules) BaseProperty.WriteToStream(r, sb, tw); + } if(rDates != null && rDates.Count != 0) + { foreach(RDateProperty r in rDates) BaseProperty.WriteToStream(r, sb, tw); + } if(exRules != null && exRules.Count != 0) - foreach(ExRuleProperty e in exRules) + { + foreach(ExRuleProperty e in exRules.Cast()) BaseProperty.WriteToStream(e, sb, tw); + } if(exDates != null && exDates.Count != 0) + { foreach(ExDateProperty e in exDates) BaseProperty.WriteToStream(e, sb, tw); + } if(this.ExcludeStartDateTime) tw.Write("X-EWSOFTWARE-EXCLUDESTART:1\r\n"); @@ -459,9 +487,9 @@ public DateTimeInstanceCollection InstancesBetween(DateTime fromDate, DateTime t Period p; DateTime endDate, tempDate1 = DateTime.MaxValue, tempDate2; int idx, count; - string timeZoneID = this.TimeZoneId; + string? timeZoneID = this.TimeZoneId; - PeriodCollection periods = new PeriodCollection(); + PeriodCollection periods = []; DateTime startDate = this.StartDateTime.TimeZoneDateTime; Duration dur = this.InstanceDuration; @@ -522,6 +550,7 @@ public DateTimeInstanceCollection InstancesBetween(DateTime fromDate, DateTime t // Add on recurrence dates within the range foreach(RDateProperty rd in this.RecurDates) + { if(rd.ValueLocation != ValLocValue.Period) { // If it's not a period, use the component's duration. If it's only a date, assume it's @@ -556,6 +585,7 @@ public DateTimeInstanceCollection InstancesBetween(DateTime fromDate, DateTime t periods.Add(new Period(tempDate1, tempDate2)); } } + } // Expand exception rules and filter out those instances count = periods.Count; @@ -576,13 +606,17 @@ public DateTimeInstanceCollection InstancesBetween(DateTime fromDate, DateTime t er.Recurrence.RecurUntil = tempDate1; foreach(DateTime dt in recurDates) + { for(idx = 0; idx < count; idx++) + { if(periods[idx].StartDateTime == dt) { periods.RemoveAt(idx); idx--; count--; } + } + } } // Filter out any exception dates @@ -604,30 +638,38 @@ public DateTimeInstanceCollection InstancesBetween(DateTime fromDate, DateTime t } } else + { if(dt >= fromDate.Date && dt <= toDate.Date) + { for(idx = 0; idx < count; idx++) + { if(periods[idx].StartDateTime.Date == dt) { periods.RemoveAt(idx); idx--; count--; } + } + } + } } // Sort the periods and remove duplicates periods.Sort(true); for(idx = 1; idx < count; idx++) + { if(periods[idx] == periods[idx - 1]) { periods.RemoveAt(idx); idx--; count--; } + } } // Now convert the periods to DateTimeInstances that include the necessary time zone information - DateTimeInstanceCollection dtic = new DateTimeInstanceCollection(); + DateTimeInstanceCollection dtic = []; DateTimeInstance dti, dtiEnd; // Always in local time if there is no time zone ID @@ -658,12 +700,14 @@ public DateTimeInstanceCollection InstancesBetween(DateTime fromDate, DateTime t if(!dtic.Contains(dti)) dtic.Add(dti); else + { if(dti.StartIsDaylightSavingTime) { dti.StartDateTime = dti.StartDateTime.AddHours(1); dti.EndDateTime = dti.EndDateTime.AddHours(1); dtic.Add(dti); } + } } return dtic; // And finally, we are done diff --git a/Source/EWSPDIData/PDIObjects/VAlarm.cs b/Source/EWSPDIData/PDIObjects/VAlarm.cs index 83c0e45..ff7a8a3 100644 --- a/Source/EWSPDIData/PDIObjects/VAlarm.cs +++ b/Source/EWSPDIData/PDIObjects/VAlarm.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VAlarm.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the VAlarm object used by vCalendar and iCalendar objects // @@ -41,20 +40,20 @@ public class VAlarm : CalendarObject //===================================================================== // Single alarm properties - private ActionProperty action; - private TriggerProperty trigger; - private RepeatProperty repeat; - private DurationProperty duration; - private SummaryProperty summary; - private DescriptionProperty desc; + private ActionProperty action = null!; + private TriggerProperty trigger = null!; + private RepeatProperty repeat = null!; + private DurationProperty duration = null!; + private SummaryProperty summary = null!; + private DescriptionProperty desc = null!; // Alarm property collections. There can be one or more of each of these properties so they are stored // in a collection. - private AttendeePropertyCollection attendees; - private AttachPropertyCollection attachments; + private AttendeePropertyCollection attendees = null!; + private AttachPropertyCollection attachments = null!; // This is a catch-all that holds all unknown or extension properties - private CustomPropertyCollection customProps; + private CustomPropertyCollection customProps = null!; #endregion @@ -76,8 +75,7 @@ public ActionProperty Action { get { - if(action == null) - action = new ActionProperty(); + action ??= new ActionProperty(); return action; } @@ -91,8 +89,7 @@ public TriggerProperty Trigger { get { - if(trigger == null) - trigger = new TriggerProperty(); + trigger ??= new TriggerProperty(); return trigger; } @@ -105,8 +102,7 @@ public RepeatProperty Repeat { get { - if(repeat == null) - repeat = new RepeatProperty(); + repeat ??= new RepeatProperty(); return repeat; } @@ -119,8 +115,7 @@ public DurationProperty Duration { get { - if(duration == null) - duration = new DurationProperty(); + duration ??= new DurationProperty(); return duration; } @@ -134,8 +129,7 @@ public SummaryProperty Summary { get { - if(summary == null) - summary = new SummaryProperty(); + summary ??= new SummaryProperty(); return summary; } @@ -150,8 +144,7 @@ public DescriptionProperty Description { get { - if(desc == null) - desc = new DescriptionProperty(); + desc ??= new DescriptionProperty(); return desc; } @@ -166,8 +159,7 @@ public AttendeePropertyCollection Attendees { get { - if(attendees == null) - attendees = new AttendeePropertyCollection(); + attendees ??= []; return attendees; } @@ -185,8 +177,7 @@ public AttachPropertyCollection Attachments { get { - if(attachments == null) - attachments = new AttachPropertyCollection(); + attachments ??= []; return attachments; } @@ -200,8 +191,7 @@ public CustomPropertyCollection CustomProperties { get { - if(customProps == null) - customProps = new CustomPropertyCollection(); + customProps ??= []; return customProps; } @@ -230,7 +220,7 @@ public VAlarm() /// A clone of the object public override object Clone() { - VAlarm o = new VAlarm(); + VAlarm o = new(); o.Clone(this); return o; } @@ -263,16 +253,16 @@ protected override void Clone(PDIObject p) /// public override void ClearProperties() { - action = null; - trigger = null; - repeat = null; - duration = null; - summary = null; - desc = null; - - attendees = null; - attachments = null; - customProps = null; + action = null!; + trigger = null!; + repeat = null!; + duration = null!; + summary = null!; + desc = null!; + + attendees = null!; + attachments = null!; + customProps = null!; } /// @@ -298,14 +288,9 @@ public override void PropagateVersion() if(desc != null) desc.Version = this.Version; - if(attendees != null) - attendees.PropagateVersion(this.Version); - - if(attachments != null) - attachments.PropagateVersion(this.Version); - - if(customProps != null) - customProps.PropagateVersion(this.Version); + attendees?.PropagateVersion(this.Version); + attachments?.PropagateVersion(this.Version); + customProps?.PropagateVersion(this.Version); } /// @@ -315,7 +300,7 @@ public override void PropagateVersion() /// unique time zone IDs used by the calendar objects. public override void TimeZonesUsed(StringCollection timeZoneIds) { - CalendarObject.AddTimeZoneIfUsed(trigger, timeZoneIds); + AddTimeZoneIfUsed(trigger, timeZoneIds); } /// @@ -324,9 +309,9 @@ public override void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public override void UpdateTimeZoneId(string oldId, string newId) + public override void UpdateTimeZoneId(string? oldId, string? newId) { - CalendarObject.UpdatePropertyTimeZoneId(trigger, oldId, newId); + UpdatePropertyTimeZoneId(trigger, oldId, newId); } /// @@ -336,9 +321,9 @@ public override void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public override void ApplyTimeZone(VTimeZone vTimeZone) + public override void ApplyTimeZone(VTimeZone? vTimeZone) { - CalendarObject.ApplyPropertyTimeZone(trigger, vTimeZone); + ApplyPropertyTimeZone(trigger, vTimeZone); } /// @@ -348,9 +333,9 @@ public override void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public override void SetTimeZone(VTimeZone vTimeZone) + public override void SetTimeZone(VTimeZone? vTimeZone) { - CalendarObject.SetPropertyTimeZone(trigger, vTimeZone); + SetPropertyTimeZone(trigger, vTimeZone); } /// @@ -361,15 +346,15 @@ public override void SetTimeZone(VTimeZone vTimeZone) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream. - public override void WriteToStream(TextWriter tw, StringBuilder sb) + public override void WriteToStream(TextWriter tw, StringBuilder? sb) { - StringBuilder sbVCal = null; - PropagateVersion(); // If vCalendar 1.0, write in alternate format if(this.Version == SpecificationVersions.vCalendar10) { + StringBuilder? sbVCal; + // If using a StringWriter, append directly to it if(sb == null) sbVCal = ((StringWriter)tw).GetStringBuilder(); @@ -574,19 +559,25 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(desc, sb, tw); if(attendees != null && attendees.Count != 0) + { foreach(AttendeeProperty a in attendees) BaseProperty.WriteToStream(a, sb, tw); + } if(attachments != null && attachments.Count != 0) + { foreach(AttachProperty a in attachments) BaseProperty.WriteToStream(a, sb, tw); + } break; } // Add any custom properties if(customProps != null && customProps.Count != 0) + { foreach(CustomProperty c in customProps) BaseProperty.WriteToStream(c, sb, tw); + } tw.Write("END:VALARM\r\n"); } @@ -598,12 +589,12 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is VAlarm a)) + if(obj is not VAlarm a) return false; // The ToString() method returns a text representation of the alarm based on all of its settings so // it's a reliable way to tell if two instances are the same. - return (this == a || this.ToString() == a.ToString()); + return this == a || this.ToString() == a.ToString(); } /// diff --git a/Source/EWSPDIData/PDIObjects/VAlarmCollection.cs b/Source/EWSPDIData/PDIObjects/VAlarmCollection.cs index 9dfe306..ecac565 100644 --- a/Source/EWSPDIData/PDIObjects/VAlarmCollection.cs +++ b/Source/EWSPDIData/PDIObjects/VAlarmCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VAlarmCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/06/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for VAlarm objects // @@ -85,7 +84,7 @@ public void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public void UpdateTimeZoneId(string oldId, string newId) + public void UpdateTimeZoneId(string? oldId, string? newId) { foreach(VAlarm a in this) a.UpdateTimeZoneId(oldId, newId); @@ -100,7 +99,7 @@ public void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public void ApplyTimeZone(VTimeZone vTimeZone) + public void ApplyTimeZone(VTimeZone? vTimeZone) { foreach(VAlarm a in this) a.ApplyTimeZone(vTimeZone); @@ -115,7 +114,7 @@ public void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public void SetTimeZone(VTimeZone vTimeZone) + public void SetTimeZone(VTimeZone? vTimeZone) { foreach(VAlarm a in this) a.SetTimeZone(vTimeZone); diff --git a/Source/EWSPDIData/PDIObjects/VCalendar.cs b/Source/EWSPDIData/PDIObjects/VCalendar.cs index e5b363c..5bedd37 100644 --- a/Source/EWSPDIData/PDIObjects/VCalendar.cs +++ b/Source/EWSPDIData/PDIObjects/VCalendar.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VCalendar.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/20/2013 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the vCalendar/iCalendar object. // @@ -45,24 +44,24 @@ public class VCalendar : CalendarObject, ISerializable, IDisposable //===================================================================== // Single calendar properties - private ProductIdProperty prodId; + private ProductIdProperty prodId = null!; - private CalendarScaleProperty calScale; // iCalendar only - private MethodProperty method; // iCalendar only + private CalendarScaleProperty calScale = null!; // iCalendar only + private MethodProperty method = null!; // iCalendar only - private GeographicPositionProperty geo; // vCalendar only - private TimeZoneProperty tz; // vCalendar only - private DaylightProperty daylight; // vCalendar only + private GeographicPositionProperty geo = null!; // vCalendar only + private TimeZoneProperty tz = null!; // vCalendar only + private DaylightProperty daylight = null!; // vCalendar only // Calendar property collections. There can be one or more of each of these properties so they are // stored in a collection. - private VEventCollection events; - private VToDoCollection todos; - private VJournalCollection journals; // iCalendar only - private VFreeBusyCollection freebusy; // iCalendar only + private VEventCollection events = null!; + private VToDoCollection todos = null!; + private VJournalCollection journals = null!; // iCalendar only + private VFreeBusyCollection freebusy = null!; // iCalendar only // This is a catch-all that holds all unknown or extension properties - private CustomPropertyCollection customProps; + private CustomPropertyCollection customProps = null!; #endregion @@ -84,8 +83,7 @@ public ProductIdProperty ProductId { get { - if(prodId == null) - prodId = new ProductIdProperty(); + prodId ??= new ProductIdProperty(); return prodId; } @@ -100,8 +98,7 @@ public CalendarScaleProperty CalendarScale { get { - if(calScale == null) - calScale = new CalendarScaleProperty(); + calScale ??= new CalendarScaleProperty(); return calScale; } @@ -116,8 +113,7 @@ public MethodProperty Method { get { - if(method == null) - method = new MethodProperty(); + method ??= new MethodProperty(); return method; } @@ -132,8 +128,7 @@ public GeographicPositionProperty VCalendarGeographicPosition { get { - if(geo == null) - geo = new GeographicPositionProperty(); + geo ??= new GeographicPositionProperty(); return geo; } @@ -148,8 +143,7 @@ public TimeZoneProperty VCalendarTimeZone { get { - if(tz == null) - tz = new TimeZoneProperty(); + tz ??= new TimeZoneProperty(); return tz; } @@ -164,8 +158,7 @@ public DaylightProperty VCalendarDaylightRule { get { - if(daylight == null) - daylight = new DaylightProperty(); + daylight ??= new DaylightProperty(); return daylight; } @@ -183,7 +176,7 @@ public DaylightProperty VCalendarDaylightRule /// introduce some method of letting the sub-objects like events know who their containing calendar is in /// order to get a reference to a time zone collection. /// - public static VTimeZoneCollection TimeZones { get; } = new VTimeZoneCollection(); + public static VTimeZoneCollection TimeZones { get; } = []; /// /// This is used to hold a set of event (VEVENT) objects associated with the calendar @@ -193,8 +186,7 @@ public VEventCollection Events { get { - if(events == null) - events = new VEventCollection(); + events ??= []; return events; } @@ -208,8 +200,7 @@ public VToDoCollection ToDos { get { - if(todos == null) - todos = new VToDoCollection(); + todos ??= []; return todos; } @@ -224,8 +215,7 @@ public VJournalCollection Journals { get { - if(journals == null) - journals = new VJournalCollection(); + journals ??= []; return journals; } @@ -240,8 +230,7 @@ public VFreeBusyCollection FreeBusys { get { - if(freebusy == null) - freebusy = new VFreeBusyCollection(); + freebusy ??= []; return freebusy; } @@ -255,8 +244,7 @@ public CustomPropertyCollection CustomProperties { get { - if(customProps == null) - customProps = new CustomPropertyCollection(); + customProps ??= []; return customProps; } @@ -364,8 +352,7 @@ protected virtual void Dispose(bool disposing) [SecurityCritical] public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { - if(info != null) - info.AddValue("VCALENDAR", this.ToString()); + info?.AddValue("VCALENDAR", this.ToString()); } #endregion @@ -378,7 +365,7 @@ public virtual void GetObjectData(SerializationInfo info, StreamingContext conte /// A clone of the object public override object Clone() { - VCalendar o = new VCalendar(); + VCalendar o = new(); o.Clone(this); return o; } @@ -415,19 +402,19 @@ protected override void Clone(PDIObject p) /// collection will not be cleared. If you want it cleared, you must do it manually. public override void ClearProperties() { - prodId = null; - calScale = null; - method = null; - geo = null; - tz = null; - daylight = null; - - events = null; - todos = null; - journals = null; - freebusy = null; - - customProps = null; + prodId = null!; + calScale = null!; + method = null!; + geo = null!; + tz = null!; + daylight = null!; + + events = null!; + todos = null!; + journals = null!; + freebusy = null!; + + customProps = null!; } /// @@ -438,14 +425,9 @@ public override void PropagateVersion() if(prodId != null) prodId.Version = this.Version; - if(events != null) - events.PropagateVersion(this.Version); - - if(todos != null) - todos.PropagateVersion(this.Version); - - if(customProps != null) - customProps.PropagateVersion(this.Version); + events?.PropagateVersion(this.Version); + todos?.PropagateVersion(this.Version); + customProps?.PropagateVersion(this.Version); if(geo != null) geo.Version = this.Version; @@ -466,12 +448,8 @@ public override void PropagateVersion() if(method != null) method.Version = this.Version; - if(journals != null) - journals.PropagateVersion(this.Version); - - if(freebusy != null) - freebusy.PropagateVersion(this.Version); - + journals?.PropagateVersion(this.Version); + freebusy?.PropagateVersion(this.Version); TimeZones.PropagateVersion(this.Version); } } @@ -483,17 +461,10 @@ public override void PropagateVersion() /// unique time zone IDs used by the calendar objects. public override void TimeZonesUsed(StringCollection timeZoneIds) { - if(events != null) - events.TimeZonesUsed(timeZoneIds); - - if(todos != null) - todos.TimeZonesUsed(timeZoneIds); - - if(journals != null) - journals.TimeZonesUsed(timeZoneIds); - - if(freebusy != null) - freebusy.TimeZonesUsed(timeZoneIds); + events?.TimeZonesUsed(timeZoneIds); + todos?.TimeZonesUsed(timeZoneIds); + journals?.TimeZonesUsed(timeZoneIds); + freebusy?.TimeZonesUsed(timeZoneIds); } /// @@ -502,19 +473,12 @@ public override void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public override void UpdateTimeZoneId(string oldId, string newId) + public override void UpdateTimeZoneId(string? oldId, string? newId) { - if(events != null) - events.UpdateTimeZoneId(oldId, newId); - - if(todos != null) - todos.UpdateTimeZoneId(oldId, newId); - - if(journals != null) - journals.UpdateTimeZoneId(oldId, newId); - - if(freebusy != null) - freebusy.UpdateTimeZoneId(oldId, newId); + events?.UpdateTimeZoneId(oldId, newId); + todos?.UpdateTimeZoneId(oldId, newId); + journals?.UpdateTimeZoneId(oldId, newId); + freebusy?.UpdateTimeZoneId(oldId, newId); } /// @@ -524,19 +488,12 @@ public override void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public override void ApplyTimeZone(VTimeZone vTimeZone) + public override void ApplyTimeZone(VTimeZone? vTimeZone) { - if(events != null) - events.ApplyTimeZone(vTimeZone); - - if(todos != null) - todos.ApplyTimeZone(vTimeZone); - - if(journals != null) - journals.ApplyTimeZone(vTimeZone); - - if(freebusy != null) - freebusy.ApplyTimeZone(vTimeZone); + events?.ApplyTimeZone(vTimeZone); + todos?.ApplyTimeZone(vTimeZone); + journals?.ApplyTimeZone(vTimeZone); + freebusy?.ApplyTimeZone(vTimeZone); } /// @@ -546,19 +503,12 @@ public override void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public override void SetTimeZone(VTimeZone vTimeZone) + public override void SetTimeZone(VTimeZone? vTimeZone) { - if(events != null) - events.SetTimeZone(vTimeZone); - - if(todos != null) - todos.SetTimeZone(vTimeZone); - - if(journals != null) - journals.SetTimeZone(vTimeZone); - - if(freebusy != null) - freebusy.SetTimeZone(vTimeZone); + events?.SetTimeZone(vTimeZone); + todos?.SetTimeZone(vTimeZone); + journals?.SetTimeZone(vTimeZone); + freebusy?.SetTimeZone(vTimeZone); } /// @@ -570,7 +520,7 @@ public override void SetTimeZone(VTimeZone vTimeZone) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream. - public override void WriteToStream(TextWriter tw, StringBuilder sb) + public override void WriteToStream(TextWriter tw, StringBuilder? sb) { PropagateVersion(); @@ -598,7 +548,8 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) // Time zones are usually listed first. Build a list to see which time zones are needed and // stream only those. - StringCollection tzIds = new StringCollection(); + StringCollection tzIds = []; + this.TimeZonesUsed(tzIds); if(tzIds.Count != 0) @@ -609,8 +560,10 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) try { foreach(VTimeZone tz in TimeZones) - if(tzIds.Contains(tz.TimeZoneId.Value)) + { + if(tzIds.Contains(tz.TimeZoneId.Value!)) tz.WriteToStream(tw, sb); + } } finally { @@ -619,25 +572,35 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) } if(journals != null && journals.Count != 0) + { foreach(VJournal j in journals) j.WriteToStream(tw, sb); + } if(freebusy != null && freebusy.Count != 0) + { foreach(VFreeBusy f in freebusy) f.WriteToStream(tw, sb); + } } if(events != null && events.Count != 0) + { foreach(VEvent v in events) v.WriteToStream(tw, sb); + } if(todos != null && todos.Count != 0) + { foreach(VToDo t in todos) t.WriteToStream(tw, sb); + } if(customProps != null && customProps.Count != 0) + { foreach(CustomProperty c in customProps) BaseProperty.WriteToStream(c, sb, tw); + } tw.Write("END:VCALENDAR\r\n"); } @@ -649,12 +612,12 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is VCalendar c)) + if(obj is not VCalendar c) return false; // The ToString() method returns a text representation of the calendar based on all of its settings // so it's a reliable way to tell if two instances are the same. - return (this == c || this.ToString() == c.ToString()); + return this == c || this.ToString() == c.ToString(); } /// @@ -694,8 +657,8 @@ private void tzid_TimeZoneIdChanged(object sender, TimeZoneIdChangedEventArgs e) /// standard rule. /// This is used to return the start of daylight saving time for the returned /// daylight rule. - private static void FindRules(DateTime convertDate, string timeZoneId, bool useLocalTime, - out ObservanceRule standardRule, out ObservanceRule daylightRule, out DateTime standardDate, + private static void FindRules(DateTime convertDate, string? timeZoneId, bool useLocalTime, + out ObservanceRule? standardRule, out ObservanceRule? daylightRule, out DateTime standardDate, out DateTime dstDate) { DateTime startDate; @@ -704,7 +667,7 @@ private static void FindRules(DateTime convertDate, string timeZoneId, bool useL standardRule = daylightRule = null; standardDate = dstDate = DateTime.MinValue; - VTimeZone vtz = TimeZones[timeZoneId]; + VTimeZone? vtz = TimeZones[timeZoneId]; if(vtz == null) return; @@ -731,6 +694,7 @@ private static void FindRules(DateTime convertDate, string timeZoneId, bool useL { // Check for an RDATE that matches. foreach(RDateProperty rdt in or.RecurDates) + { if(rdt.TimeZoneDateTime.Year == convertDate.Year) { standardRule = or; @@ -742,9 +706,11 @@ private static void FindRules(DateTime convertDate, string timeZoneId, bool useL break; } + } // If there wasn't one, check the RRULEs if(standardRule == null) + { foreach(RRuleProperty rrule in or.RecurrenceRules) { // Set the start date and resolve the recurrence @@ -765,6 +731,7 @@ private static void FindRules(DateTime convertDate, string timeZoneId, bool useL break; } } + } // If it doesn't have any RDATEs or RRULEs and the year is on or after the start date year, // use the start date. @@ -784,6 +751,7 @@ private static void FindRules(DateTime convertDate, string timeZoneId, bool useL { // Check for an RDATE that matches. foreach(RDateProperty rdt in or.RecurDates) + { if(rdt.TimeZoneDateTime.Year == convertDate.Year) { daylightRule = or; @@ -795,9 +763,11 @@ private static void FindRules(DateTime convertDate, string timeZoneId, bool useL break; } + } // If there wasn't one, check the RRULEs if(daylightRule == null) + { foreach(RRuleProperty rrule in or.RecurrenceRules) { // Set the start date and resolve the recurrence @@ -818,6 +788,7 @@ private static void FindRules(DateTime convertDate, string timeZoneId, bool useL break; } } + } // If it doesn't have any RDATEs or RRULEs and the year is on or after the start date year, // use the start date. @@ -847,7 +818,7 @@ private static void FindRules(DateTime convertDate, string timeZoneId, bool useL /// collection. /// The date/time in Universal Time (UTC) if the specified time zone is found in the collection /// or the unmodified date/time if it cannot be found. - public static DateTime TimeZoneTimeToUtc(DateTime convertDate, string timeZoneId) + public static DateTime TimeZoneTimeToUtc(DateTime convertDate, string? timeZoneId) { // We won't adjust values in year 1 or year 9999 as we could underflow or overflow the date/time @@ -856,7 +827,7 @@ public static DateTime TimeZoneTimeToUtc(DateTime convertDate, string timeZoneId return convertDate; // Get the observance rules to use in the conversion - FindRules(convertDate, timeZoneId, false, out ObservanceRule standardRule, out ObservanceRule daylightRule, + FindRules(convertDate, timeZoneId, false, out ObservanceRule? standardRule, out ObservanceRule? daylightRule, out DateTime standardDate, out DateTime dstDate); // If neither observance rule was found, use it as-is @@ -891,16 +862,16 @@ public static DateTime TimeZoneTimeToUtc(DateTime convertDate, string timeZoneId { // Northern hemisphere if(convertDate >= dstDate && convertDate < standardDate) - return convertDate.Add(daylightRule.OffsetTo.TimeSpanValue.Negate()); + return convertDate.Add(daylightRule!.OffsetTo.TimeSpanValue.Negate()); - return convertDate.Add(standardRule.OffsetTo.TimeSpanValue.Negate()); + return convertDate.Add(standardRule!.OffsetTo.TimeSpanValue.Negate()); } // Southern hemisphere if(convertDate >= standardDate && convertDate < dstDate) - return convertDate.Add(standardRule.OffsetTo.TimeSpanValue.Negate()); + return convertDate.Add(standardRule!.OffsetTo.TimeSpanValue.Negate()); - return convertDate.Add(daylightRule.OffsetTo.TimeSpanValue.Negate()); + return convertDate.Add(daylightRule!.OffsetTo.TimeSpanValue.Negate()); } /// @@ -914,11 +885,11 @@ public static DateTime TimeZoneTimeToUtc(DateTime convertDate, string timeZoneId /// collection or the unmodified date/time information if it cannot be found. /// For this method, the end date/time information in the returned object is the same as the /// start date/time information and it has a zero length duration. - public static DateTimeInstance UtcToTimeZoneTime(DateTime convertDate, string timeZoneId) + public static DateTimeInstance UtcToTimeZoneTime(DateTime convertDate, string? timeZoneId) { - TimeZoneNameProperty tzn; + TimeZoneNameProperty? tzn; - DateTimeInstance dti = new DateTimeInstance(convertDate); + DateTimeInstance dti = new(convertDate); // We won't adjust values in year 1 or year 9999 as we could underflow or overflow the date/time // object. @@ -928,8 +899,8 @@ public static DateTimeInstance UtcToTimeZoneTime(DateTime convertDate, string ti dti.TimeZoneId = timeZoneId; // Get the observance rules to use in the conversion - FindRules(convertDate.ToLocalTime(), timeZoneId, false, out ObservanceRule standardRule, - out ObservanceRule daylightRule, out DateTime standardDate, out DateTime dstDate); + FindRules(convertDate.ToLocalTime(), timeZoneId, false, out ObservanceRule? standardRule, + out ObservanceRule? daylightRule, out DateTime standardDate, out DateTime dstDate); // If neither observance rule was found, use it as-is if(standardRule == null && daylightRule == null) @@ -937,12 +908,16 @@ public static DateTimeInstance UtcToTimeZoneTime(DateTime convertDate, string ti // Keep the day part of the returned values but use the time value from the rule and shift it to UTC if(standardRule != null) + { standardDate = standardDate.Date.Add(standardRule.StartDateTime.DateTimeValue.TimeOfDay.Add( standardRule.OffsetFrom.TimeSpanValue.Negate())); + } if(daylightRule != null) + { dstDate = dstDate.Date.Add(daylightRule.StartDateTime.DateTimeValue.TimeOfDay.Add( daylightRule.OffsetFrom.TimeSpanValue.Negate())); + } // Standard rule only? if(standardRule != null && daylightRule == null) @@ -952,7 +927,7 @@ public static DateTimeInstance UtcToTimeZoneTime(DateTime convertDate, string ti if(convertDate >= standardDate) { tzn = standardRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.Add(standardRule.OffsetTo.TimeSpanValue); } else @@ -974,7 +949,7 @@ public static DateTimeInstance UtcToTimeZoneTime(DateTime convertDate, string ti { dti.StartIsDaylightSavingTime = dti.EndIsDaylightSavingTime = true; tzn = daylightRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.Add(daylightRule.OffsetTo.TimeSpanValue); } else @@ -994,31 +969,34 @@ public static DateTimeInstance UtcToTimeZoneTime(DateTime convertDate, string ti if(convertDate >= dstDate && convertDate < standardDate) { dti.StartIsDaylightSavingTime = dti.EndIsDaylightSavingTime = true; - tzn = daylightRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = daylightRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.Add(daylightRule.OffsetTo.TimeSpanValue); } else { - tzn = standardRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = standardRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.Add(standardRule.OffsetTo.TimeSpanValue); } } - else // Southern hemisphere + else + { + // Southern hemisphere if(convertDate >= standardDate && convertDate < dstDate) { - tzn = standardRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = standardRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.Add(standardRule.OffsetTo.TimeSpanValue); } else { dti.StartIsDaylightSavingTime = dti.EndIsDaylightSavingTime = true; - tzn = daylightRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = daylightRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.Add(daylightRule.OffsetTo.TimeSpanValue); } + } return dti; } @@ -1034,9 +1012,9 @@ public static DateTimeInstance UtcToTimeZoneTime(DateTime convertDate, string ti /// collection or the unmodified date/time information if it cannot be found. /// For this method, the end date/time information in the returned object is the same as the /// start date/time information and it has a zero length duration. - public static DateTimeInstance TimeZoneTimeToLocalTime(DateTime convertDate, string timeZoneId) + public static DateTimeInstance TimeZoneTimeToLocalTime(DateTime convertDate, string? timeZoneId) { - DateTimeInstance dti = new DateTimeInstance(convertDate); + DateTimeInstance dti = new(convertDate); // We won't adjust values in year 1 or year 9999 as we could underflow or overflow the date/time // object. @@ -1044,8 +1022,8 @@ public static DateTimeInstance TimeZoneTimeToLocalTime(DateTime convertDate, str return dti; // Get the observance rules to use in the conversion - FindRules(convertDate, timeZoneId, false, out ObservanceRule standardRule, - out ObservanceRule daylightRule, out DateTime standardDate, out DateTime daylightDate); + FindRules(convertDate, timeZoneId, false, out ObservanceRule? standardRule, + out ObservanceRule? daylightRule, out DateTime standardDate, out DateTime daylightDate); // If neither observance rule was found, use it as-is if(standardRule == null && daylightRule == null) @@ -1062,8 +1040,10 @@ public static DateTimeInstance TimeZoneTimeToLocalTime(DateTime convertDate, str standardRule.OffsetTo.TimeSpanValue.Negate()).ToLocalTime(); } else + { dti.StartDateTime = dti.EndDateTime = convertDate.Add( standardRule.OffsetFrom.TimeSpanValue.Negate()).ToLocalTime(); + } // Base the time zone name on the local time's DST setting if(TimeZoneInfo.Local.IsDaylightSavingTime(dti.StartDateTime)) @@ -1092,8 +1072,10 @@ public static DateTimeInstance TimeZoneTimeToLocalTime(DateTime convertDate, str daylightRule.OffsetTo.TimeSpanValue.Negate()).ToLocalTime(); } else + { dti.StartDateTime = dti.EndDateTime = convertDate.Add( daylightRule.OffsetFrom.TimeSpanValue.Negate()).ToLocalTime(); + } // Base the time zone name on the local time's DST setting if(TimeZoneInfo.Local.IsDaylightSavingTime(dti.StartDateTime)) @@ -1119,17 +1101,21 @@ public static DateTimeInstance TimeZoneTimeToLocalTime(DateTime convertDate, str convertDate = convertDate.AddHours(1); dti.StartDateTime = dti.EndDateTime = convertDate.Add( - daylightRule.OffsetTo.TimeSpanValue.Negate()).ToLocalTime(); + daylightRule!.OffsetTo.TimeSpanValue.Negate()).ToLocalTime(); } else + { dti.StartDateTime = dti.EndDateTime = convertDate.Add( - standardRule.OffsetTo.TimeSpanValue.Negate()).ToLocalTime(); + standardRule!.OffsetTo.TimeSpanValue.Negate()).ToLocalTime(); + } } - else // Southern hemisphere + else + { + // Southern hemisphere if(convertDate >= standardDate && convertDate < daylightDate) { dti.StartDateTime = dti.EndDateTime = convertDate.Add( - standardRule.OffsetTo.TimeSpanValue.Negate()).ToLocalTime(); + standardRule!.OffsetTo.TimeSpanValue.Negate()).ToLocalTime(); } else { @@ -1138,8 +1124,9 @@ public static DateTimeInstance TimeZoneTimeToLocalTime(DateTime convertDate, str convertDate = convertDate.AddHours(1); dti.StartDateTime = dti.EndDateTime = convertDate.Add( - daylightRule.OffsetTo.TimeSpanValue.Negate()).ToLocalTime(); + daylightRule!.OffsetTo.TimeSpanValue.Negate()).ToLocalTime(); } + } // Base the time zone name on the local time's DST setting if(TimeZoneInfo.Local.IsDaylightSavingTime(dti.StartDateTime)) @@ -1164,11 +1151,11 @@ public static DateTimeInstance TimeZoneTimeToLocalTime(DateTime convertDate, str /// collection or the unmodified date/time information if it cannot be found. /// For this method, the end date/time information in the returned object is the same as the /// start date/time information and it has a zero length duration. - public static DateTimeInstance LocalTimeToTimeZoneTime(DateTime convertDate, string timeZoneId) + public static DateTimeInstance LocalTimeToTimeZoneTime(DateTime convertDate, string? timeZoneId) { - TimeZoneNameProperty tzn; + TimeZoneNameProperty? tzn; - DateTimeInstance dti = new DateTimeInstance(convertDate); + DateTimeInstance dti = new(convertDate); // We won't adjust values in year 1 or year 9999 as we could underflow or overflow the date/time // object @@ -1178,7 +1165,7 @@ public static DateTimeInstance LocalTimeToTimeZoneTime(DateTime convertDate, str dti.TimeZoneId = timeZoneId; // Get the observance rules to use in the conversion - FindRules(convertDate, timeZoneId, true, out ObservanceRule standardRule, out ObservanceRule daylightRule, + FindRules(convertDate, timeZoneId, true, out ObservanceRule? standardRule, out ObservanceRule? daylightRule, out DateTime standardDate, out DateTime daylightDate); // If neither observance rule was found, use it as-is @@ -1193,7 +1180,7 @@ public static DateTimeInstance LocalTimeToTimeZoneTime(DateTime convertDate, str if(convertDate >= standardDate) { tzn = standardRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.ToUniversalTime().Add(standardRule.OffsetTo.TimeSpanValue); } else @@ -1216,7 +1203,7 @@ public static DateTimeInstance LocalTimeToTimeZoneTime(DateTime convertDate, str // No need to adjust if in the missing hour as the conversion to UTC will fix it up dti.StartIsDaylightSavingTime = dti.EndIsDaylightSavingTime = true; tzn = daylightRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.ToUniversalTime().Add(daylightRule.OffsetTo.TimeSpanValue); } else @@ -1237,32 +1224,35 @@ public static DateTimeInstance LocalTimeToTimeZoneTime(DateTime convertDate, str { // No need to adjust if in the missing hour as the conversion to UTC will fix it up dti.StartIsDaylightSavingTime = dti.EndIsDaylightSavingTime = true; - tzn = daylightRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = daylightRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.ToUniversalTime().Add(daylightRule.OffsetTo.TimeSpanValue); } else { - tzn = standardRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = standardRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.ToUniversalTime().Add(standardRule.OffsetTo.TimeSpanValue); } } - else // Southern hemisphere + else + { + // Southern hemisphere if(convertDate >= standardDate && convertDate < daylightDate) { - tzn = standardRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = standardRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.ToUniversalTime().Add(standardRule.OffsetTo.TimeSpanValue); } else { // No need to adjust if in the missing hour as the conversion to UTC will fix it up dti.StartIsDaylightSavingTime = dti.EndIsDaylightSavingTime = true; - tzn = daylightRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = daylightRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; dti.StartDateTime = dti.EndDateTime = convertDate.ToUniversalTime().Add(daylightRule.OffsetTo.TimeSpanValue); } + } return dti; } @@ -1282,7 +1272,7 @@ public static DateTimeInstance LocalTimeToTimeZoneTime(DateTime convertDate, str /// be found. /// For this method, the end date/time information in the returned object is the same as the /// start date/time information and it has a zero length duration. - public static DateTimeInstance TimeZoneToTimeZone(DateTime convertDate, string sourceId, string destId) + public static DateTimeInstance TimeZoneToTimeZone(DateTime convertDate, string? sourceId, string? destId) { DateTimeInstance dti; @@ -1292,7 +1282,7 @@ public static DateTimeInstance TimeZoneToTimeZone(DateTime convertDate, string s else { // Convert it from the source time zone to UTC and then from UTC to the destination time zone - dti = VCalendar.UtcToTimeZoneTime(VCalendar.TimeZoneTimeToUtc(convertDate, sourceId), destId); + dti = UtcToTimeZoneTime(TimeZoneTimeToUtc(convertDate, sourceId), destId); } return dti; @@ -1309,11 +1299,11 @@ public static DateTimeInstance TimeZoneToTimeZone(DateTime convertDate, string s /// unmodified date/time information if it cannot be found. /// For this method, the end date/time information in the returned object is the same as the /// start date/time information and it has a zero length duration. - public static DateTimeInstance TimeZoneTimeInfo(DateTime infoDate, string timeZoneId) + public static DateTimeInstance TimeZoneTimeInfo(DateTime infoDate, string? timeZoneId) { - TimeZoneNameProperty tzn; + TimeZoneNameProperty? tzn; - DateTimeInstance dti = new DateTimeInstance(infoDate); + DateTimeInstance dti = new(infoDate); // We won't adjust values in year 1 or year 9999 as we could underflow or overflow the date/time // object. @@ -1323,7 +1313,7 @@ public static DateTimeInstance TimeZoneTimeInfo(DateTime infoDate, string timeZo dti.TimeZoneId = timeZoneId; // Get the observance rules to use in the conversion - FindRules(infoDate, timeZoneId, false, out ObservanceRule standardRule, out ObservanceRule daylightRule, + FindRules(infoDate, timeZoneId, false, out ObservanceRule? standardRule, out ObservanceRule? daylightRule, out DateTime standardDate, out DateTime dstDate); // If neither observance rule was found, use it as-is @@ -1336,7 +1326,7 @@ public static DateTimeInstance TimeZoneTimeInfo(DateTime infoDate, string timeZo if(infoDate >= standardDate) { tzn = standardRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; } else // We don't have a time zone name for this case dti.StartIsDaylightSavingTime = dti.EndIsDaylightSavingTime = true; @@ -1356,7 +1346,7 @@ public static DateTimeInstance TimeZoneTimeInfo(DateTime infoDate, string timeZo dti.StartIsDaylightSavingTime = dti.EndIsDaylightSavingTime = true; tzn = daylightRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; } return dti; @@ -1374,20 +1364,22 @@ public static DateTimeInstance TimeZoneTimeInfo(DateTime infoDate, string timeZo dti.StartDateTime = dti.EndDateTime = infoDate.AddHours(1); dti.StartIsDaylightSavingTime = dti.EndIsDaylightSavingTime = true; - tzn = daylightRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = daylightRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; } else { - tzn = standardRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = standardRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; } } - else // Southern hemisphere + else + { + // Southern hemisphere if(infoDate >= standardDate && infoDate < dstDate) { - tzn = standardRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = standardRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; } else { @@ -1396,9 +1388,10 @@ public static DateTimeInstance TimeZoneTimeInfo(DateTime infoDate, string timeZo dti.StartDateTime = dti.EndDateTime = infoDate.AddHours(1); dti.StartIsDaylightSavingTime = dti.EndIsDaylightSavingTime = true; - tzn = daylightRule.TimeZoneNames[CultureInfo.CurrentCulture.Name]; - dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value; + tzn = daylightRule!.TimeZoneNames[CultureInfo.CurrentCulture.Name]; + dti.StartTimeZoneName = dti.EndTimeZoneName = (tzn == null) ? String.Empty : tzn.Value!; } + } return dti; } diff --git a/Source/EWSPDIData/PDIObjects/VCard.cs b/Source/EWSPDIData/PDIObjects/VCard.cs index f81e7a7..26fd6f0 100644 --- a/Source/EWSPDIData/PDIObjects/VCard.cs +++ b/Source/EWSPDIData/PDIObjects/VCard.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : VCard.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 07/24/2020 -// Note : Copyright 2004-2020, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the vCard object and a collection of vCard objects // @@ -45,51 +45,51 @@ public class VCard : PDIObject, ISerializable //===================================================================== // Single vCard properties - private KindProperty kind; - private FormattedNameProperty fn; - private NameProperty name; - private TitleProperty title; - private RoleProperty role; - private MailerProperty mailer; - private OrganizationProperty org; - private UniqueIdProperty uid; - private BirthDateProperty bday; - private AnniversaryProperty anniversary; - private LastRevisionProperty rev; - private TimeZoneProperty tz; - private GeographicPositionProperty geo; - private PublicKeyProperty key; - private PhotoProperty photo; - private LogoProperty logo; - private SoundProperty sound; + private KindProperty kind = null!; + private FormattedNameProperty fn = null!; + private NameProperty name = null!; + private TitleProperty title = null!; + private RoleProperty role = null!; + private MailerProperty mailer = null!; + private OrganizationProperty org = null!; + private UniqueIdProperty uid = null!; + private BirthDateProperty bday = null!; + private AnniversaryProperty anniversary = null!; + private LastRevisionProperty rev = null!; + private TimeZoneProperty tz = null!; + private GeographicPositionProperty geo = null!; + private PublicKeyProperty key = null!; + private PhotoProperty photo = null!; + private LogoProperty logo = null!; + private SoundProperty sound = null!; // vCard property collections. There can be one or more of each of these properties so they are stored // in a collection. - private NotePropertyCollection notes; - private AddressPropertyCollection addrs; - private LabelPropertyCollection labels; - private TelephonePropertyCollection phones; - private EMailPropertyCollection email; - private UrlPropertyCollection urls; - private AgentPropertyCollection agents; - private ClientPidMapPropertyCollection pidMaps; - private MemberPropertyCollection members; - private RelatedPropertyCollection related; + private NotePropertyCollection notes = null!; + private AddressPropertyCollection addrs = null!; + private LabelPropertyCollection labels = null!; + private TelephonePropertyCollection phones = null!; + private EMailPropertyCollection email = null!; + private UrlPropertyCollection urls = null!; + private AgentPropertyCollection agents = null!; + private ClientPidMapPropertyCollection pidMaps = null!; + private MemberPropertyCollection members = null!; + private RelatedPropertyCollection related = null!; // This is a catch-all that holds all unknown or extension properties - private CustomPropertyCollection customProps; + private CustomPropertyCollection customProps = null!; // These properties are only valid for the 3.0 and later specifications - private MimeNameProperty mimeName; - private MimeSourceProperty mimeSource; - private ProductIdProperty prodId; - private NicknameProperty nickname; - private SortStringProperty sortString; - private ClassificationProperty classification; - private CategoriesProperty categories; + private MimeNameProperty mimeName = null!; + private MimeSourceProperty mimeSource = null!; + private ProductIdProperty prodId = null!; + private NicknameProperty nickname = null!; + private SortStringProperty sortString = null!; + private ClassificationProperty classification = null!; + private CategoriesProperty categories = null!; // These properties are valid for the 4.0 specification only - private GenderProperty gender; + private GenderProperty gender = null!; #endregion @@ -121,7 +121,7 @@ public override SpecificationVersions Version /// /// vCards support grouping. If grouped, this property will contain the name of the group with /// which the vCard is associated. - public string Group { get; set; } + public string? Group { get; set; } /// /// This property is used to set or get a flag indicating whether or not the PROFILE:VCARD property @@ -138,8 +138,7 @@ public KindProperty Kind { get { - if(kind == null) - kind = new KindProperty(); + kind ??= new KindProperty(); return kind; } @@ -152,8 +151,7 @@ public FormattedNameProperty FormattedName { get { - if(fn == null) - fn = new FormattedNameProperty(); + fn ??= new FormattedNameProperty(); return fn; } @@ -166,8 +164,7 @@ public NameProperty Name { get { - if(name == null) - name = new NameProperty(); + name ??= new NameProperty() { Version = this.Version }; return name; } @@ -180,8 +177,7 @@ public TitleProperty Title { get { - if(title == null) - title = new TitleProperty(); + title ??= new TitleProperty(); return title; } @@ -194,8 +190,7 @@ public RoleProperty Role { get { - if(role == null) - role = new RoleProperty(); + role ??= new RoleProperty(); return role; } @@ -208,8 +203,7 @@ public MailerProperty Mailer { get { - if(mailer == null) - mailer = new MailerProperty(); + mailer ??= new MailerProperty(); return mailer; } @@ -240,8 +234,7 @@ public OrganizationProperty Organization { get { - if(org == null) - org = new OrganizationProperty(); + org ??= new OrganizationProperty() { Version = this.Version }; return org; } @@ -272,8 +265,7 @@ public BirthDateProperty BirthDate { get { - if(bday == null) - bday = new BirthDateProperty(); + bday ??= new BirthDateProperty() { Version = this.Version }; return bday; } @@ -286,8 +278,7 @@ public AnniversaryProperty Anniversary { get { - if(anniversary == null) - anniversary = new AnniversaryProperty(); + anniversary ??= new AnniversaryProperty(); return anniversary; } @@ -300,8 +291,7 @@ public LastRevisionProperty LastRevision { get { - if(rev == null) - rev = new LastRevisionProperty(); + rev ??= new LastRevisionProperty() { Version = this.Version }; return rev; } @@ -314,8 +304,7 @@ public TimeZoneProperty TimeZone { get { - if(tz == null) - tz = new TimeZoneProperty(); + tz ??= new TimeZoneProperty(); return tz; } @@ -328,8 +317,7 @@ public GeographicPositionProperty GeographicPosition { get { - if(geo == null) - geo = new GeographicPositionProperty(); + geo ??= new GeographicPositionProperty(); return geo; } @@ -342,8 +330,7 @@ public PublicKeyProperty PublicKey { get { - if(key == null) - key = new PublicKeyProperty(); + key ??= new PublicKeyProperty() { Version = this.Version }; return key; } @@ -356,8 +343,7 @@ public PhotoProperty Photo { get { - if(photo == null) - photo = new PhotoProperty(); + photo ??= new PhotoProperty() { Version = this.Version }; return photo; } @@ -370,8 +356,7 @@ public LogoProperty Logo { get { - if(logo == null) - logo = new LogoProperty(); + logo ??= new LogoProperty() { Version = this.Version }; return logo; } @@ -384,8 +369,7 @@ public SoundProperty Sound { get { - if(sound == null) - sound = new SoundProperty(); + sound ??= new SoundProperty() { Version = this.Version }; return sound; } @@ -399,8 +383,7 @@ public NotePropertyCollection Notes { get { - if(notes == null) - notes = new NotePropertyCollection(); + notes ??= []; return notes; } @@ -414,8 +397,7 @@ public AddressPropertyCollection Addresses { get { - if(addrs == null) - addrs = new AddressPropertyCollection(); + addrs ??= []; return addrs; } @@ -429,8 +411,7 @@ public LabelPropertyCollection Labels { get { - if(labels == null) - labels = new LabelPropertyCollection(); + labels ??= []; return labels; } @@ -444,8 +425,7 @@ public TelephonePropertyCollection Telephones { get { - if(phones == null) - phones = new TelephonePropertyCollection(); + phones ??= []; return phones; } @@ -459,8 +439,7 @@ public EMailPropertyCollection EMailAddresses { get { - if(email == null) - email = new EMailPropertyCollection(); + email ??= []; return email; } @@ -475,8 +454,7 @@ public UrlPropertyCollection Urls { get { - if(urls == null) - urls = new UrlPropertyCollection(); + urls ??= []; return urls; } @@ -491,8 +469,7 @@ public AgentPropertyCollection Agents { get { - if(agents == null) - agents = new AgentPropertyCollection(); + agents ??= []; return agents; } @@ -506,8 +483,7 @@ public ClientPidMapPropertyCollection ClientPidMaps { get { - if(pidMaps == null) - pidMaps = new ClientPidMapPropertyCollection(); + pidMaps ??= []; return pidMaps; } @@ -521,8 +497,7 @@ public MemberPropertyCollection Members { get { - if(members == null) - members = new MemberPropertyCollection(); + members ??= []; return members; } @@ -536,8 +511,7 @@ public RelatedPropertyCollection Related { get { - if(related == null) - related = new RelatedPropertyCollection(); + related ??= []; return related; } @@ -552,8 +526,7 @@ public CustomPropertyCollection CustomProperties { get { - if(customProps == null) - customProps = new CustomPropertyCollection(); + customProps ??= []; return customProps; } @@ -570,8 +543,7 @@ public MimeNameProperty MimeName { get { - if(mimeName == null) - mimeName = new MimeNameProperty(); + mimeName ??= new MimeNameProperty(); return mimeName; } @@ -585,8 +557,7 @@ public MimeSourceProperty MimeSource { get { - if(mimeSource == null) - mimeSource = new MimeSourceProperty(); + mimeSource ??= new MimeSourceProperty(); return mimeSource; } @@ -600,8 +571,7 @@ public ProductIdProperty ProductId { get { - if(prodId == null) - prodId = new ProductIdProperty(); + prodId ??= new ProductIdProperty(); return prodId; } @@ -615,8 +585,7 @@ public NicknameProperty Nickname { get { - if(nickname == null) - nickname = new NicknameProperty(); + nickname ??= new NicknameProperty(); return nickname; } @@ -630,8 +599,7 @@ public SortStringProperty SortString { get { - if(sortString == null) - sortString = new SortStringProperty(); + sortString ??= new SortStringProperty(); return sortString; } @@ -645,8 +613,7 @@ public ClassificationProperty Classification { get { - if(classification == null) - classification = new ClassificationProperty(); + classification ??= new ClassificationProperty(); return classification; } @@ -661,8 +628,7 @@ public CategoriesProperty Categories { get { - if(categories == null) - categories = new CategoriesProperty(); + categories ??= new CategoriesProperty(); return categories; } @@ -677,8 +643,7 @@ public GenderProperty Gender { get { - if(gender == null) - gender = new GenderProperty(); + gender ??= new GenderProperty(); return gender; } @@ -727,8 +692,7 @@ protected VCard(SerializationInfo info, StreamingContext context) : this() [SecurityCritical] public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { - if(info != null) - info.AddValue("VCARD", this.ToString()); + info?.AddValue("VCARD", this.ToString()); } #endregion @@ -741,7 +705,7 @@ public virtual void GetObjectData(SerializationInfo info, StreamingContext conte /// A clone of the object public override object Clone() { - VCard o = new VCard(); + VCard o = new(); o.Clone(this); return o; } @@ -809,47 +773,47 @@ public void ClearProperties() { this.Group = null; - kind = null; - fn = null; - name = null; - title = null; - role = null; - mailer = null; - org = null; - uid = null; - bday = null; - anniversary = null; - rev = null; - tz = null; - geo = null; - key = null; - photo = null; - logo = null; - sound = null; - - notes = null; - addrs = null; - labels = null; - phones = null; - email = null; - urls = null; - agents = null; - pidMaps = null; - members = null; - related = null; - customProps = null; + kind = null!; + fn = null!; + name = null!; + title = null!; + role = null!; + mailer = null!; + org = null!; + uid = null!; + bday = null!; + anniversary = null!; + rev = null!; + tz = null!; + geo = null!; + key = null!; + photo = null!; + logo = null!; + sound = null!; + + notes = null!; + addrs = null!; + labels = null!; + phones = null!; + email = null!; + urls = null!; + agents = null!; + pidMaps = null!; + members = null!; + related = null!; + customProps = null!; this.AddProfile = false; - mimeName = null; - mimeSource = null; - prodId = null; - nickname = null; - sortString = null; - classification = null; - categories = null; + mimeName = null!; + mimeSource = null!; + prodId = null!; + nickname = null!; + sortString = null!; + classification = null!; + categories = null!; - gender = null; + gender = null!; } /// @@ -902,29 +866,14 @@ public void PropagateVersion() if(sound != null) sound.Version = this.Version; - if(notes != null) - notes.PropagateVersion(this.Version); - - if(addrs != null) - addrs.PropagateVersion(this.Version); - - if(labels != null) - labels.PropagateVersion(this.Version); - - if(phones != null) - phones.PropagateVersion(this.Version); - - if(email != null) - email.PropagateVersion(this.Version); - - if(urls != null) - urls.PropagateVersion(this.Version); - - if(agents != null) - agents.PropagateVersion(this.Version); - - if(customProps != null) - customProps.PropagateVersion(this.Version); + notes?.PropagateVersion(this.Version); + addrs?.PropagateVersion(this.Version); + labels?.PropagateVersion(this.Version); + phones?.PropagateVersion(this.Version); + email?.PropagateVersion(this.Version); + urls?.PropagateVersion(this.Version); + agents?.PropagateVersion(this.Version); + customProps?.PropagateVersion(this.Version); if(this.Version != SpecificationVersions.vCard21) { @@ -960,14 +909,9 @@ public void PropagateVersion() if(gender != null) gender.Version = this.Version; - if(members != null) - members.PropagateVersion(this.Version); - - if(related != null) - related.PropagateVersion(this.Version); - - if(pidMaps != null) - pidMaps.PropagateVersion(this.Version); + members?.PropagateVersion(this.Version); + related?.PropagateVersion(this.Version); + pidMaps?.PropagateVersion(this.Version); } } } @@ -979,12 +923,12 @@ public void PropagateVersion() /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is VCard vc)) + if(obj is not VCard vc) return false; // The ToString() method returns a text representation of the vCard based on all of its settings so // it's a reliable way to tell if two instances are the same. - return (this == vc || this.ToString() == vc.ToString()); + return this == vc || this.ToString() == vc.ToString(); } /// @@ -1004,11 +948,10 @@ public override int GetHashCode() /// Returns a text description of the vCard suitable for saving to a PDI data stream public override string ToString() { - using(var sw = new StringWriter(new StringBuilder(1024), CultureInfo.InvariantCulture)) - { - this.WriteToStream(sw, null); - return sw.ToString(); - } + using var sw = new StringWriter(new StringBuilder(1024), CultureInfo.InvariantCulture); + + this.WriteToStream(sw, null); + return sw.ToString(); } /// @@ -1060,7 +1003,7 @@ public void WriteToStream(TextWriter tw) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they convert /// themselves to a string or write themselves to a PDI data stream. - public void WriteToStream(TextWriter tw, StringBuilder sb) + public void WriteToStream(TextWriter tw, StringBuilder? sb) { // If Formatted Name is undefined, try to set it based on Name if(fn == null || fn.Value == "Unknown") @@ -1079,10 +1022,12 @@ public void WriteToStream(TextWriter tw, StringBuilder sb) if(this.Version == SpecificationVersions.vCard21) tw.Write("VERSION:2.1\r\n"); else + { if(this.Version == SpecificationVersions.vCard30) tw.Write("VERSION:3.0\r\n"); else tw.Write("VERSION:4.0\r\n"); + } if(this.Version == SpecificationVersions.vCard30 && this.AddProfile) tw.Write("PROFILE:VCARD\r\n"); @@ -1114,8 +1059,10 @@ public void WriteToStream(TextWriter tw, StringBuilder sb) } if(related != null && related.Count != 0) + { foreach(var r in related) BaseProperty.WriteToStream(r, sb, tw); + } } // These two are required properties @@ -1150,32 +1097,46 @@ public void WriteToStream(TextWriter tw, StringBuilder sb) } if(addrs != null && addrs.Count != 0) + { foreach(AddressProperty a in addrs) BaseProperty.WriteToStream(a, sb, tw); + } if(this.Version != SpecificationVersions.vCard40 && labels != null && labels.Count != 0) + { foreach(LabelProperty l in labels) BaseProperty.WriteToStream(l, sb, tw); + } if(phones != null && phones.Count != 0) + { foreach(TelephoneProperty t in phones) BaseProperty.WriteToStream(t, sb, tw); + } if(email != null && email.Count != 0) + { foreach(EMailProperty e in email) BaseProperty.WriteToStream(e, sb, tw); + } if(agents != null && agents.Count != 0) + { foreach(AgentProperty a in agents) BaseProperty.WriteToStream(a, sb, tw); + } if(notes != null && notes.Count != 0) + { foreach(NoteProperty n in notes) BaseProperty.WriteToStream(n, sb, tw); + } if(urls != null && urls.Count != 0) + { foreach(UrlProperty u in urls) BaseProperty.WriteToStream(u, sb, tw); + } BaseProperty.WriteToStream(tz, sb, tw); BaseProperty.WriteToStream(geo, sb, tw); @@ -1187,8 +1148,10 @@ public void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(uid, sb, tw); if(pidMaps != null && pidMaps.Count != 0 && this.Version == SpecificationVersions.vCard40) + { foreach(var p in pidMaps) BaseProperty.WriteToStream(p, sb, tw); + } BaseProperty.WriteToStream(key, sb, tw); BaseProperty.WriteToStream(photo, sb, tw); @@ -1196,8 +1159,10 @@ public void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(sound, sb, tw); if(customProps != null && customProps.Count != 0) + { foreach(CustomProperty c in customProps) BaseProperty.WriteToStream(c, sb, tw); + } if(this.Group != null) { diff --git a/Source/EWSPDIData/PDIObjects/VCardCollection.cs b/Source/EWSPDIData/PDIObjects/VCardCollection.cs index 6e32f9d..88cbeef 100644 --- a/Source/EWSPDIData/PDIObjects/VCardCollection.cs +++ b/Source/EWSPDIData/PDIObjects/VCardCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VCardCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/06/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for VCard objects // @@ -70,24 +69,28 @@ public VCardCollection(IList cards) : base(cards) /// returned if it does not exist in the collection. /// This is thrown if an attempt is made to set an item using a /// unique ID that does not exist in the collection. - public VCard this[string uniqueId] + public VCard? this[string uniqueId] { get { - for(int idx = 0; idx < base.Count; idx++) + for(int idx = 0; idx < this.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) return base[idx]; + } return null; } set { - for(int idx = 0; idx < base.Count; idx++) + for(int idx = 0; idx < this.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) { - base[idx] = value; + base[idx] = value!; return; } + } throw new ArgumentException(LR.GetString("ExUIDNotFound")); } @@ -103,11 +106,10 @@ public VCard this[string uniqueId] /// A string containing the entire vCard collection public override string ToString() { - using(var sw = new StringWriter(new StringBuilder(4096), CultureInfo.InvariantCulture)) - { - this.WriteToStream(sw); - return sw.ToString(); - } + using var sw = new StringWriter(new StringBuilder(4096), CultureInfo.InvariantCulture); + + this.WriteToStream(sw); + return sw.ToString(); } /// @@ -158,9 +160,9 @@ public override string ToString() /// public void WriteToStream(TextWriter tw) { - StringBuilder sb = null; + StringBuilder? sb = null; - if(!(tw is StringWriter)) + if(tw is not StringWriter) sb = new StringBuilder(256); foreach(VCard c in this) diff --git a/Source/EWSPDIData/PDIObjects/VEvent.cs b/Source/EWSPDIData/PDIObjects/VEvent.cs index d8ad9e3..3d4dcd1 100644 --- a/Source/EWSPDIData/PDIObjects/VEvent.cs +++ b/Source/EWSPDIData/PDIObjects/VEvent.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VEvent.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the VEvent object used by vCalendar and iCalendar objects // @@ -38,41 +37,41 @@ public class VEvent : RecurringObject //===================================================================== // Single event properties - private ClassificationProperty classification; - private CategoriesProperty categories; - private ResourcesProperty resources; - private UrlProperty url; - private UniqueIdProperty uid; - private GeographicPositionProperty geo; // iCalendar only - private LastModifiedProperty lastMod; - private DateCreatedProperty dateCreated; - private StartDateProperty startDate; - private EndDateProperty endDate; - private TimeStampProperty dateStamp; // iCalendar only - private SummaryProperty summary; - private DescriptionProperty desc; - private LocationProperty location; - private PriorityProperty priority; - private SequenceProperty sequence; - private TimeTransparencyProperty transp; - private RecurrenceCountProperty rNum; // vCalendar only - private CommentProperty comment; // iCalendar only - private OrganizerProperty organizer; // iCalendar only - private RecurrenceIdProperty recurId; // iCalendar only - private StatusProperty status; - private DurationProperty duration; // iCalendar only + private ClassificationProperty classification = null!; + private CategoriesProperty categories = null!; + private ResourcesProperty resources = null!; + private UrlProperty url = null!; + private UniqueIdProperty uid = null!; + private GeographicPositionProperty geo = null!; // iCalendar only + private LastModifiedProperty lastMod = null!; + private DateCreatedProperty dateCreated = null!; + private StartDateProperty startDate = null!; + private EndDateProperty endDate = null!; + private TimeStampProperty dateStamp = null!; // iCalendar only + private SummaryProperty summary = null!; + private DescriptionProperty desc = null!; + private LocationProperty location = null!; + private PriorityProperty priority = null!; + private SequenceProperty sequence = null!; + private TimeTransparencyProperty transp = null!; + private RecurrenceCountProperty rNum = null!; // vCalendar only + private CommentProperty comment = null!; // iCalendar only + private OrganizerProperty organizer = null!; // iCalendar only + private RecurrenceIdProperty recurId = null!; // iCalendar only + private StatusProperty status = null!; + private DurationProperty duration = null!; // iCalendar only // Event property collections. There can be one or more of each of these properties so they are stored // in a collection. - private ContactPropertyCollection contacts; // iCalendar only - private AttendeePropertyCollection attendees; - private RelatedToPropertyCollection relatedTo; - private AttachPropertyCollection attachments; - private RequestStatusPropertyCollection reqStats; // iCalendar only - private VAlarmCollection alarms; + private ContactPropertyCollection contacts = null!; // iCalendar only + private AttendeePropertyCollection attendees = null!; + private RelatedToPropertyCollection relatedTo = null!; + private AttachPropertyCollection attachments = null!; + private RequestStatusPropertyCollection reqStats = null!; // iCalendar only + private VAlarmCollection alarms = null!; // This is a catch-all that holds all unknown or extension properties - private CustomPropertyCollection customProps; + private CustomPropertyCollection customProps = null!; #endregion @@ -93,8 +92,7 @@ public UrlProperty Url { get { - if(url == null) - url = new UrlProperty(); + url ??= new UrlProperty(); return url; } @@ -127,8 +125,7 @@ public LastModifiedProperty LastModified { get { - if(lastMod == null) - lastMod = new LastModifiedProperty(); + lastMod ??= new LastModifiedProperty(); return lastMod; } @@ -144,8 +141,7 @@ public GeographicPositionProperty GeographicPosition { get { - if(geo == null) - geo = new GeographicPositionProperty(); + geo ??= new GeographicPositionProperty(); return geo; } @@ -158,8 +154,7 @@ public ClassificationProperty Classification { get { - if(classification == null) - classification = new ClassificationProperty(); + classification ??= new ClassificationProperty(); return classification; } @@ -173,8 +168,7 @@ public CategoriesProperty Categories { get { - if(categories == null) - categories = new CategoriesProperty(); + categories ??= new CategoriesProperty(); return categories; } @@ -187,8 +181,7 @@ public ResourcesProperty Resources { get { - if(resources == null) - resources = new ResourcesProperty(); + resources ??= new ResourcesProperty(); return resources; } @@ -201,8 +194,7 @@ public DateCreatedProperty DateCreated { get { - if(dateCreated == null) - dateCreated = new DateCreatedProperty(); + dateCreated ??= new DateCreatedProperty(); return dateCreated; } @@ -215,8 +207,7 @@ public override StartDateProperty StartDateTime { get { - if(startDate == null) - startDate = new StartDateProperty(); + startDate ??= new StartDateProperty(); return startDate; } @@ -234,8 +225,7 @@ public EndDateProperty EndDateTime { get { - if(endDate == null) - endDate = new EndDateProperty(); + endDate ??= new EndDateProperty(); return endDate; } @@ -249,8 +239,7 @@ public TimeStampProperty TimeStamp { get { - if(dateStamp == null) - dateStamp = new TimeStampProperty { DateTimeValue = DateTime.Now }; + dateStamp ??= new TimeStampProperty { DateTimeValue = DateTime.Now }; return dateStamp; } @@ -263,8 +252,7 @@ public SummaryProperty Summary { get { - if(summary == null) - summary = new SummaryProperty(); + summary ??= new SummaryProperty(); return summary; } @@ -277,8 +265,7 @@ public DescriptionProperty Description { get { - if(desc == null) - desc = new DescriptionProperty(); + desc ??= new DescriptionProperty(); return desc; } @@ -291,8 +278,7 @@ public LocationProperty Location { get { - if(location == null) - location = new LocationProperty(); + location ??= new LocationProperty(); return location; } @@ -305,8 +291,7 @@ public PriorityProperty Priority { get { - if(priority == null) - priority = new PriorityProperty(); + priority ??= new PriorityProperty(); return priority; } @@ -319,8 +304,7 @@ public SequenceProperty Sequence { get { - if(sequence == null) - sequence = new SequenceProperty(); + sequence ??= new SequenceProperty(); return sequence; } @@ -333,8 +317,7 @@ public TimeTransparencyProperty Transparency { get { - if(transp == null) - transp = new TimeTransparencyProperty(); + transp ??= new TimeTransparencyProperty(); return transp; } @@ -349,8 +332,7 @@ public RecurrenceCountProperty RecurrenceCount { get { - if(rNum == null) - rNum = new RecurrenceCountProperty(); + rNum ??= new RecurrenceCountProperty(); return rNum; } @@ -365,8 +347,7 @@ public CommentProperty Comment { get { - if(comment == null) - comment = new CommentProperty(); + comment ??= new CommentProperty(); return comment; } @@ -381,8 +362,7 @@ public OrganizerProperty Organizer { get { - if(organizer == null) - organizer = new OrganizerProperty(); + organizer ??= new OrganizerProperty(); return organizer; } @@ -397,8 +377,7 @@ public RecurrenceIdProperty RecurrenceId { get { - if(recurId == null) - recurId = new RecurrenceIdProperty(); + recurId ??= new RecurrenceIdProperty(); return recurId; } @@ -411,8 +390,7 @@ public StatusProperty Status { get { - if(status == null) - status = new StatusProperty(); + status ??= new StatusProperty(); return status; } @@ -430,8 +408,7 @@ public DurationProperty Duration { get { - if(duration == null) - duration = new DurationProperty(); + duration ??= new DurationProperty(); return duration; } @@ -446,8 +423,7 @@ public ContactPropertyCollection Contacts { get { - if(contacts == null) - contacts = new ContactPropertyCollection(); + contacts ??= []; return contacts; } @@ -461,8 +437,7 @@ public AttendeePropertyCollection Attendees { get { - if(attendees == null) - attendees = new AttendeePropertyCollection(); + attendees ??= []; return attendees; } @@ -476,8 +451,7 @@ public RelatedToPropertyCollection RelatedTo { get { - if(relatedTo == null) - relatedTo = new RelatedToPropertyCollection(); + relatedTo ??= []; return relatedTo; } @@ -491,8 +465,7 @@ public AttachPropertyCollection Attachments { get { - if(attachments == null) - attachments = new AttachPropertyCollection(); + attachments ??= []; return attachments; } @@ -506,8 +479,7 @@ public RequestStatusPropertyCollection RequestStatuses { get { - if(reqStats == null) - reqStats = new RequestStatusPropertyCollection(); + reqStats ??= []; return reqStats; } @@ -524,8 +496,7 @@ public VAlarmCollection Alarms { get { - if(alarms == null) - alarms = new VAlarmCollection(); + alarms ??= []; return alarms; } @@ -539,8 +510,7 @@ public CustomPropertyCollection CustomProperties { get { - if(customProps == null) - customProps = new CustomPropertyCollection(); + customProps ??= []; return customProps; } @@ -578,7 +548,7 @@ public override Duration InstanceDuration /// /// It returns the of the /// property. - public override string TimeZoneId => this.StartDateTime.TimeZoneId; + public override string? TimeZoneId => this.StartDateTime.TimeZoneId; #endregion @@ -604,7 +574,7 @@ public VEvent() /// A clone of the object public override object Clone() { - VEvent o = new VEvent(); + VEvent o = new(); o.Clone(this); return o; } @@ -660,38 +630,38 @@ protected override void Clone(PDIObject p) /// public override void ClearProperties() { - classification = null; - categories = null; - resources = null; - url = null; - uid = null; - geo = null; - lastMod = null; - dateCreated = null; - startDate = null; - endDate = null; - dateStamp = null; - summary = null; - desc = null; - location = null; - priority = null; - sequence = null; - transp = null; - rNum = null; - comment = null; - organizer = null; - recurId = null; - status = null; - duration = null; - - contacts = null; - attendees = null; - relatedTo = null; - attachments = null; - reqStats = null; - alarms = null; - - customProps = null; + classification = null!; + categories = null!; + resources = null!; + url = null!; + uid = null!; + geo = null!; + lastMod = null!; + dateCreated = null!; + startDate = null!; + endDate = null!; + dateStamp = null!; + summary = null!; + desc = null!; + location = null!; + priority = null!; + sequence = null!; + transp = null!; + rNum = null!; + comment = null!; + organizer = null!; + recurId = null!; + status = null!; + duration = null!; + + contacts = null!; + attendees = null!; + relatedTo = null!; + attachments = null!; + reqStats = null!; + alarms = null!; + + customProps = null!; base.ClearProperties(); } @@ -750,11 +720,8 @@ public override void PropagateVersion() if(recurId != null) recurId.Version = this.Version; - if(contacts != null) - contacts.PropagateVersion(this.Version); - - if(reqStats != null) - reqStats.PropagateVersion(this.Version); + contacts?.PropagateVersion(this.Version); + reqStats?.PropagateVersion(this.Version); } if(summary != null) @@ -781,20 +748,11 @@ public override void PropagateVersion() if(duration != null) duration.Version = this.Version; - if(attendees != null) - attendees.PropagateVersion(this.Version); - - if(relatedTo != null) - relatedTo.PropagateVersion(this.Version); - - if(attachments != null) - attachments.PropagateVersion(this.Version); - - if(alarms != null) - alarms.PropagateVersion(this.Version); - - if(customProps != null) - customProps.PropagateVersion(this.Version); + attendees?.PropagateVersion(this.Version); + relatedTo?.PropagateVersion(this.Version); + attachments?.PropagateVersion(this.Version); + alarms?.PropagateVersion(this.Version); + customProps?.PropagateVersion(this.Version); base.PropagateVersion(); } @@ -806,12 +764,11 @@ public override void PropagateVersion() /// unique time zone IDs used by the calendar objects. public override void TimeZonesUsed(StringCollection timeZoneIds) { - CalendarObject.AddTimeZoneIfUsed(startDate, timeZoneIds); - CalendarObject.AddTimeZoneIfUsed(endDate, timeZoneIds); - CalendarObject.AddTimeZoneIfUsed(recurId, timeZoneIds); + AddTimeZoneIfUsed(startDate, timeZoneIds); + AddTimeZoneIfUsed(endDate, timeZoneIds); + AddTimeZoneIfUsed(recurId, timeZoneIds); - if(alarms != null) - alarms.TimeZonesUsed(timeZoneIds); + alarms?.TimeZonesUsed(timeZoneIds); base.TimeZonesUsed(timeZoneIds); } @@ -822,14 +779,13 @@ public override void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public override void UpdateTimeZoneId(string oldId, string newId) + public override void UpdateTimeZoneId(string? oldId, string? newId) { - CalendarObject.UpdatePropertyTimeZoneId(startDate, oldId, newId); - CalendarObject.UpdatePropertyTimeZoneId(endDate, oldId, newId); - CalendarObject.UpdatePropertyTimeZoneId(recurId, oldId, newId); + UpdatePropertyTimeZoneId(startDate, oldId, newId); + UpdatePropertyTimeZoneId(endDate, oldId, newId); + UpdatePropertyTimeZoneId(recurId, oldId, newId); - if(alarms != null) - alarms.UpdateTimeZoneId(oldId, newId); + alarms?.UpdateTimeZoneId(oldId, newId); base.UpdateTimeZoneId(oldId, newId); } @@ -841,14 +797,13 @@ public override void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public override void ApplyTimeZone(VTimeZone vTimeZone) + public override void ApplyTimeZone(VTimeZone? vTimeZone) { - CalendarObject.ApplyPropertyTimeZone(startDate, vTimeZone); - CalendarObject.ApplyPropertyTimeZone(endDate, vTimeZone); - CalendarObject.ApplyPropertyTimeZone(recurId, vTimeZone); + ApplyPropertyTimeZone(startDate, vTimeZone); + ApplyPropertyTimeZone(endDate, vTimeZone); + ApplyPropertyTimeZone(recurId, vTimeZone); - if(alarms != null) - alarms.ApplyTimeZone(vTimeZone); + alarms?.ApplyTimeZone(vTimeZone); base.ApplyTimeZone(vTimeZone); } @@ -860,14 +815,13 @@ public override void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public override void SetTimeZone(VTimeZone vTimeZone) + public override void SetTimeZone(VTimeZone? vTimeZone) { - CalendarObject.SetPropertyTimeZone(startDate, vTimeZone); - CalendarObject.SetPropertyTimeZone(endDate, vTimeZone); - CalendarObject.SetPropertyTimeZone(recurId, vTimeZone); + SetPropertyTimeZone(startDate, vTimeZone); + SetPropertyTimeZone(endDate, vTimeZone); + SetPropertyTimeZone(recurId, vTimeZone); - if(alarms != null) - alarms.SetTimeZone(vTimeZone); + alarms?.SetTimeZone(vTimeZone); base.SetTimeZone(vTimeZone); } @@ -880,7 +834,7 @@ public override void SetTimeZone(VTimeZone vTimeZone) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream. - public override void WriteToStream(TextWriter tw, StringBuilder sb) + public override void WriteToStream(TextWriter tw, StringBuilder? sb) { // DTSTAMP is always updated and written to reflect when the object was saved to the stream // (iCalendar 2.0 only). @@ -936,35 +890,49 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(recurId, sb, tw); if(contacts != null && contacts.Count != 0) + { foreach(ContactProperty c in contacts) BaseProperty.WriteToStream(c, sb, tw); + } if(reqStats != null && reqStats.Count != 0) + { foreach(RequestStatusProperty r in reqStats) BaseProperty.WriteToStream(r, sb, tw); + } } if(attendees != null && attendees.Count != 0) + { foreach(AttendeeProperty a in attendees) BaseProperty.WriteToStream(a, sb, tw); + } if(relatedTo != null && relatedTo.Count != 0) + { foreach(RelatedToProperty r in relatedTo) BaseProperty.WriteToStream(r, sb, tw); + } base.WriteToStream(tw, sb); if(alarms != null && alarms.Count != 0) + { foreach(VAlarm a in alarms) a.WriteToStream(tw, sb); + } if(attachments != null && attachments.Count != 0) + { foreach(AttachProperty a in attachments) BaseProperty.WriteToStream(a, sb, tw); + } if(customProps != null && customProps.Count != 0) + { foreach(CustomProperty c in customProps) BaseProperty.WriteToStream(c, sb, tw); + } tw.Write("END:VEVENT\r\n"); } @@ -976,12 +944,12 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is VEvent ev)) + if(obj is not VEvent ev) return false; // The ToString() method returns a text representation of the event based on all of its settings so // it's a reliable way to tell if two instances are the same. - return (this == ev || this.ToString() == ev.ToString()); + return this == ev || this.ToString() == ev.ToString(); } /// diff --git a/Source/EWSPDIData/PDIObjects/VEventCollection.cs b/Source/EWSPDIData/PDIObjects/VEventCollection.cs index a2c6741..03cf95c 100644 --- a/Source/EWSPDIData/PDIObjects/VEventCollection.cs +++ b/Source/EWSPDIData/PDIObjects/VEventCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VEventCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/06/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for VEvent objects // @@ -64,13 +63,15 @@ public VEventCollection(IList events) : base(events) /// returned if it does not exist in the collection. /// This is thrown if an attempt is made to set an item using a /// unique ID that does not exist in the collection. - public VEvent this[string uniqueId] + public VEvent? this[string uniqueId] { get { for(int idx = 0; idx < base.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) return base[idx]; + } return null; } @@ -79,7 +80,7 @@ public VEvent this[string uniqueId] for(int idx = 0; idx < base.Count; idx++) if(base[idx].UniqueId.Value == uniqueId) { - base[idx] = value; + base[idx] = value!; return; } @@ -133,7 +134,7 @@ public void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public void UpdateTimeZoneId(string oldId, string newId) + public void UpdateTimeZoneId(string? oldId, string? newId) { foreach(VEvent e in this) e.UpdateTimeZoneId(oldId, newId); @@ -148,7 +149,7 @@ public void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public void ApplyTimeZone(VTimeZone vTimeZone) + public void ApplyTimeZone(VTimeZone? vTimeZone) { foreach(VEvent e in this) e.ApplyTimeZone(vTimeZone); @@ -163,7 +164,7 @@ public void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public void SetTimeZone(VTimeZone vTimeZone) + public void SetTimeZone(VTimeZone? vTimeZone) { foreach(VEvent e in this) e.SetTimeZone(vTimeZone); diff --git a/Source/EWSPDIData/PDIObjects/VFreeBusy.cs b/Source/EWSPDIData/PDIObjects/VFreeBusy.cs index b418a14..bf5e332 100644 --- a/Source/EWSPDIData/PDIObjects/VFreeBusy.cs +++ b/Source/EWSPDIData/PDIObjects/VFreeBusy.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VFreeBusy.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the VFreeBusy object used by vCalendar and iCalendar objects // @@ -38,24 +37,24 @@ public class VFreeBusy : CalendarObject //===================================================================== // Single free/busy properties - private UrlProperty url; - private UniqueIdProperty uid; - private StartDateProperty startDate; - private EndDateProperty endDate; - private TimeStampProperty timeStamp; - private CommentProperty comment; - private OrganizerProperty organizer; - private DurationProperty duration; - private ContactProperty contact; + private UrlProperty url = null!; + private UniqueIdProperty uid = null!; + private StartDateProperty startDate = null!; + private EndDateProperty endDate = null!; + private TimeStampProperty timeStamp = null!; + private CommentProperty comment = null!; + private OrganizerProperty organizer = null!; + private DurationProperty duration = null!; + private ContactProperty contact = null!; // Free/busy property collections. There can be one or more of each of these properties so they are // stored in a collection. - private AttendeePropertyCollection attendees; - private RequestStatusPropertyCollection reqstats; - private FreeBusyPropertyCollection freebusy; + private AttendeePropertyCollection attendees = null!; + private RequestStatusPropertyCollection reqstats = null!; + private FreeBusyPropertyCollection freebusy = null!; // This is a catch-all that holds all unknown or extension properties - private CustomPropertyCollection customProps; + private CustomPropertyCollection customProps = null!; #endregion @@ -75,8 +74,7 @@ public UrlProperty Url { get { - if(url == null) - url = new UrlProperty(); + url ??= new UrlProperty(); return url; } @@ -108,8 +106,7 @@ public StartDateProperty StartDateTime { get { - if(startDate == null) - startDate = new StartDateProperty(); + startDate ??= new StartDateProperty(); return startDate; } @@ -122,8 +119,7 @@ public EndDateProperty EndDateTime { get { - if(endDate == null) - endDate = new EndDateProperty(); + endDate ??= new EndDateProperty(); return endDate; } @@ -137,8 +133,7 @@ public TimeStampProperty TimeStamp { get { - if(timeStamp == null) - timeStamp = new TimeStampProperty { DateTimeValue = DateTime.Now }; + timeStamp ??= new TimeStampProperty { DateTimeValue = DateTime.Now }; return timeStamp; } @@ -153,8 +148,7 @@ public CommentProperty Comment { get { - if(comment == null) - comment = new CommentProperty(); + comment ??= new CommentProperty(); return comment; } @@ -169,8 +163,7 @@ public OrganizerProperty Organizer { get { - if(organizer == null) - organizer = new OrganizerProperty(); + organizer ??= new OrganizerProperty(); return organizer; } @@ -183,8 +176,7 @@ public DurationProperty Duration { get { - if(duration == null) - duration = new DurationProperty(); + duration ??= new DurationProperty(); return duration; } @@ -197,8 +189,7 @@ public ContactProperty Contact { get { - if(contact == null) - contact = new ContactProperty(); + contact ??= new ContactProperty(); return contact; } @@ -212,8 +203,7 @@ public AttendeePropertyCollection Attendees { get { - if(attendees == null) - attendees = new AttendeePropertyCollection(); + attendees ??= []; return attendees; } @@ -227,8 +217,7 @@ public RequestStatusPropertyCollection RequestStatuses { get { - if(reqstats == null) - reqstats = new RequestStatusPropertyCollection(); + reqstats ??= []; return reqstats; } @@ -242,8 +231,7 @@ public FreeBusyPropertyCollection FreeBusy { get { - if(freebusy == null) - freebusy = new FreeBusyPropertyCollection(); + freebusy ??= []; return freebusy; } @@ -257,8 +245,7 @@ public CustomPropertyCollection CustomProperties { get { - if(customProps == null) - customProps = new CustomPropertyCollection(); + customProps ??= []; return customProps; } @@ -286,7 +273,7 @@ public VFreeBusy() /// A clone of the object public override object Clone() { - VFreeBusy o = new VFreeBusy(); + VFreeBusy o = new(); o.Clone(this); return o; } @@ -323,20 +310,20 @@ protected override void Clone(PDIObject p) /// public override void ClearProperties() { - url = null; - uid = null; - startDate = null; - endDate = null; - timeStamp = null; - comment = null; - organizer = null; - duration = null; - contact = null; - - attendees = null; - reqstats = null; - freebusy = null; - customProps = null; + url = null!; + uid = null!; + startDate = null!; + endDate = null!; + timeStamp = null!; + comment = null!; + organizer = null!; + duration = null!; + contact = null!; + + attendees = null!; + reqstats = null!; + freebusy = null!; + customProps = null!; } /// @@ -371,17 +358,10 @@ public override void PropagateVersion() if(contact != null) contact.Version = this.Version; - if(attendees != null) - attendees.PropagateVersion(this.Version); - - if(reqstats != null) - reqstats.PropagateVersion(this.Version); - - if(freebusy != null) - freebusy.PropagateVersion(this.Version); - - if(customProps != null) - customProps.PropagateVersion(this.Version); + attendees?.PropagateVersion(this.Version); + reqstats?.PropagateVersion(this.Version); + freebusy?.PropagateVersion(this.Version); + customProps?.PropagateVersion(this.Version); } /// @@ -391,8 +371,8 @@ public override void PropagateVersion() /// unique time zone IDs used by the calendar objects. public override void TimeZonesUsed(StringCollection timeZoneIds) { - CalendarObject.AddTimeZoneIfUsed(startDate, timeZoneIds); - CalendarObject.AddTimeZoneIfUsed(endDate, timeZoneIds); + AddTimeZoneIfUsed(startDate, timeZoneIds); + AddTimeZoneIfUsed(endDate, timeZoneIds); } /// @@ -401,10 +381,10 @@ public override void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public override void UpdateTimeZoneId(string oldId, string newId) + public override void UpdateTimeZoneId(string? oldId, string? newId) { - CalendarObject.UpdatePropertyTimeZoneId(startDate, oldId, newId); - CalendarObject.UpdatePropertyTimeZoneId(endDate, oldId, newId); + UpdatePropertyTimeZoneId(startDate, oldId, newId); + UpdatePropertyTimeZoneId(endDate, oldId, newId); } /// @@ -414,10 +394,10 @@ public override void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public override void ApplyTimeZone(VTimeZone vTimeZone) + public override void ApplyTimeZone(VTimeZone? vTimeZone) { - CalendarObject.ApplyPropertyTimeZone(startDate, vTimeZone); - CalendarObject.ApplyPropertyTimeZone(endDate, vTimeZone); + ApplyPropertyTimeZone(startDate, vTimeZone); + ApplyPropertyTimeZone(endDate, vTimeZone); } /// @@ -427,10 +407,10 @@ public override void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public override void SetTimeZone(VTimeZone vTimeZone) + public override void SetTimeZone(VTimeZone? vTimeZone) { - CalendarObject.SetPropertyTimeZone(startDate, vTimeZone); - CalendarObject.SetPropertyTimeZone(endDate, vTimeZone); + SetPropertyTimeZone(startDate, vTimeZone); + SetPropertyTimeZone(endDate, vTimeZone); } /// @@ -442,7 +422,7 @@ public override void SetTimeZone(VTimeZone vTimeZone) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream. - public override void WriteToStream(TextWriter tw, StringBuilder sb) + public override void WriteToStream(TextWriter tw, StringBuilder? sb) { // DTSTAMP is always updated and written to reflect when the object was saved to the stream this.TimeStamp.DateTimeValue = DateTime.Now; @@ -457,8 +437,10 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(organizer, sb, tw); if(attendees != null && attendees.Count != 0) + { foreach(AttendeeProperty a in attendees) BaseProperty.WriteToStream(a, sb, tw); + } BaseProperty.WriteToStream(contact, sb, tw); BaseProperty.WriteToStream(startDate, sb, tw); @@ -469,8 +451,10 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(timeStamp, sb, tw); if(reqstats != null && reqstats.Count != 0) + { foreach(RequestStatusProperty r in reqstats) BaseProperty.WriteToStream(r, sb, tw); + } if(freebusy != null && freebusy.Count != 0) { @@ -482,8 +466,10 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) } if(customProps != null && customProps.Count != 0) + { foreach(CustomProperty c in customProps) BaseProperty.WriteToStream(c, sb, tw); + } tw.Write("END:VFREEBUSY\r\n"); } @@ -495,12 +481,12 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is VFreeBusy fb)) + if(obj is not VFreeBusy fb) return false; // The ToString() method returns a text representation of the object based on all of its settings so // it's a reliable way to tell if two instances are the same. - return (this == fb || this.ToString() == fb.ToString()); + return this == fb || this.ToString() == fb.ToString(); } /// diff --git a/Source/EWSPDIData/PDIObjects/VFreeBusyCollection.cs b/Source/EWSPDIData/PDIObjects/VFreeBusyCollection.cs index 04d5fbc..d77047a 100644 --- a/Source/EWSPDIData/PDIObjects/VFreeBusyCollection.cs +++ b/Source/EWSPDIData/PDIObjects/VFreeBusyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VFreeBusyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/06/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for VFreeBusy objects. // @@ -64,24 +63,28 @@ public VFreeBusyCollection(IList freeBusys) : base(freeBusys) /// returned if it does not exist in the collection. /// This is thrown if an attempt is made to set an item using a /// unique ID that does not exist in the collection. - public VFreeBusy this[string uniqueId] + public VFreeBusy? this[string uniqueId] { get { for(int idx = 0; idx < base.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) return base[idx]; + } return null; } set { for(int idx = 0; idx < base.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) { - base[idx] = value; + base[idx] = value!; return; } + } throw new ArgumentException(LR.GetString("ExUIDNotFound")); } @@ -133,7 +136,7 @@ public void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public void UpdateTimeZoneId(string oldId, string newId) + public void UpdateTimeZoneId(string? oldId, string? newId) { foreach(VFreeBusy f in this) f.UpdateTimeZoneId(oldId, newId); @@ -148,7 +151,7 @@ public void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public void ApplyTimeZone(VTimeZone vTimeZone) + public void ApplyTimeZone(VTimeZone? vTimeZone) { foreach(VFreeBusy f in this) f.ApplyTimeZone(vTimeZone); @@ -163,7 +166,7 @@ public void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public void SetTimeZone(VTimeZone vTimeZone) + public void SetTimeZone(VTimeZone? vTimeZone) { foreach(VFreeBusy f in this) f.SetTimeZone(vTimeZone); diff --git a/Source/EWSPDIData/PDIObjects/VJournal.cs b/Source/EWSPDIData/PDIObjects/VJournal.cs index 9c3915e..44d54cc 100644 --- a/Source/EWSPDIData/PDIObjects/VJournal.cs +++ b/Source/EWSPDIData/PDIObjects/VJournal.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VJournal.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the VJournal object used by iCalendar objects // @@ -38,32 +37,32 @@ public class VJournal : RecurringObject //===================================================================== // Single journal properties - private ClassificationProperty classification; - private CategoriesProperty categories; - private UrlProperty url; - private UniqueIdProperty uid; - private LastModifiedProperty lastMod; - private DateCreatedProperty dateCreated; - private StartDateProperty startDate; - private TimeStampProperty timeStamp; - private SummaryProperty summary; - private DescriptionProperty desc; - private SequenceProperty sequence; - private CommentProperty comment; - private OrganizerProperty organizer; - private RecurrenceIdProperty recurId; - private StatusProperty status; + private ClassificationProperty classification = null!; + private CategoriesProperty categories = null!; + private UrlProperty url = null!; + private UniqueIdProperty uid = null!; + private LastModifiedProperty lastMod = null!; + private DateCreatedProperty dateCreated = null!; + private StartDateProperty startDate = null!; + private TimeStampProperty timeStamp = null!; + private SummaryProperty summary = null!; + private DescriptionProperty desc = null!; + private SequenceProperty sequence = null!; + private CommentProperty comment = null!; + private OrganizerProperty organizer = null!; + private RecurrenceIdProperty recurId = null!; + private StatusProperty status = null!; // Journal property collections. There can be one or more of each of these properties so they are stored // in a collection. - private ContactPropertyCollection contacts; - private AttendeePropertyCollection attendees; - private RelatedToPropertyCollection relatedTo; - private AttachPropertyCollection attachments; - private RequestStatusPropertyCollection reqStats; + private ContactPropertyCollection contacts = null!; + private AttendeePropertyCollection attendees = null!; + private RelatedToPropertyCollection relatedTo = null!; + private AttachPropertyCollection attachments = null!; + private RequestStatusPropertyCollection reqStats = null!; // This is a catch-all that holds all unknown or extension properties - private CustomPropertyCollection customProps; + private CustomPropertyCollection customProps = null!; #endregion @@ -83,8 +82,7 @@ public UrlProperty Url { get { - if(url == null) - url = new UrlProperty(); + url ??= new UrlProperty(); return url; } @@ -116,8 +114,7 @@ public LastModifiedProperty LastModified { get { - if(lastMod == null) - lastMod = new LastModifiedProperty(); + lastMod ??= new LastModifiedProperty(); return lastMod; } @@ -130,8 +127,7 @@ public ClassificationProperty Classification { get { - if(classification == null) - classification = new ClassificationProperty(); + classification ??= new ClassificationProperty(); return classification; } @@ -145,8 +141,7 @@ public CategoriesProperty Categories { get { - if(categories == null) - categories = new CategoriesProperty(); + categories ??= new CategoriesProperty(); return categories; } @@ -159,8 +154,7 @@ public DateCreatedProperty DateCreated { get { - if(dateCreated == null) - dateCreated = new DateCreatedProperty(); + dateCreated ??= new DateCreatedProperty(); return dateCreated; } @@ -173,8 +167,7 @@ public override StartDateProperty StartDateTime { get { - if(startDate == null) - startDate = new StartDateProperty(); + startDate ??= new StartDateProperty(); return startDate; } @@ -188,8 +181,7 @@ public TimeStampProperty TimeStamp { get { - if(timeStamp == null) - timeStamp = new TimeStampProperty { DateTimeValue = DateTime.Now }; + timeStamp ??= new TimeStampProperty { DateTimeValue = DateTime.Now }; return timeStamp; } @@ -202,8 +194,7 @@ public SummaryProperty Summary { get { - if(summary == null) - summary = new SummaryProperty(); + summary ??= new SummaryProperty(); return summary; } @@ -216,8 +207,7 @@ public DescriptionProperty Description { get { - if(desc == null) - desc = new DescriptionProperty(); + desc ??= new DescriptionProperty(); return desc; } @@ -230,8 +220,7 @@ public SequenceProperty Sequence { get { - if(sequence == null) - sequence = new SequenceProperty(); + sequence ??= new SequenceProperty(); return sequence; } @@ -244,8 +233,7 @@ public CommentProperty Comment { get { - if(comment == null) - comment = new CommentProperty(); + comment ??= new CommentProperty(); return comment; } @@ -258,8 +246,7 @@ public OrganizerProperty Organizer { get { - if(organizer == null) - organizer = new OrganizerProperty(); + organizer ??= new OrganizerProperty(); return organizer; } @@ -274,8 +261,7 @@ public RecurrenceIdProperty RecurrenceId { get { - if(recurId == null) - recurId = new RecurrenceIdProperty(); + recurId ??= new RecurrenceIdProperty(); return recurId; } @@ -288,8 +274,7 @@ public StatusProperty Status { get { - if(status == null) - status = new StatusProperty(); + status ??= new StatusProperty(); return status; } @@ -303,8 +288,7 @@ public ContactPropertyCollection Contacts { get { - if(contacts == null) - contacts = new ContactPropertyCollection(); + contacts ??= []; return contacts; } @@ -318,8 +302,7 @@ public AttendeePropertyCollection Attendees { get { - if(attendees == null) - attendees = new AttendeePropertyCollection(); + attendees ??= []; return attendees; } @@ -333,8 +316,7 @@ public RelatedToPropertyCollection RelatedTo { get { - if(relatedTo == null) - relatedTo = new RelatedToPropertyCollection(); + relatedTo ??= []; return relatedTo; } @@ -348,8 +330,7 @@ public AttachPropertyCollection Attachments { get { - if(attachments == null) - attachments = new AttachPropertyCollection(); + attachments ??= []; return attachments; } @@ -363,8 +344,7 @@ public RequestStatusPropertyCollection RequestStatuses { get { - if(reqStats == null) - reqStats = new RequestStatusPropertyCollection(); + reqStats ??= []; return reqStats; } @@ -378,8 +358,7 @@ public CustomPropertyCollection CustomProperties { get { - if(customProps == null) - customProps = new CustomPropertyCollection(); + customProps ??= []; return customProps; } @@ -406,7 +385,7 @@ public override Duration InstanceDuration /// /// It returns the of the /// property. - public override string TimeZoneId => this.StartDateTime.TimeZoneId; + public override string? TimeZoneId => this.StartDateTime.TimeZoneId; #endregion @@ -431,7 +410,7 @@ public VJournal() /// A clone of the object public override object Clone() { - VJournal o = new VJournal(); + VJournal o = new(); o.Clone(this); return o; } @@ -478,28 +457,28 @@ protected override void Clone(PDIObject p) /// public override void ClearProperties() { - classification = null; - categories = null; - url = null; - uid = null; - lastMod = null; - dateCreated = null; - startDate = null; - timeStamp = null; - summary = null; - desc = null; - sequence = null; - comment = null; - organizer = null; - recurId = null; - status = null; - - contacts = null; - attendees = null; - relatedTo = null; - attachments = null; - reqStats = null; - customProps = null; + classification = null!; + categories = null!; + url = null!; + uid = null!; + lastMod = null!; + dateCreated = null!; + startDate = null!; + timeStamp = null!; + summary = null!; + desc = null!; + sequence = null!; + comment = null!; + organizer = null!; + recurId = null!; + status = null!; + + contacts = null!; + attendees = null!; + relatedTo = null!; + attachments = null!; + reqStats = null!; + customProps = null!; base.ClearProperties(); } @@ -554,23 +533,12 @@ public override void PropagateVersion() if(status != null) status.Version = this.Version; - if(contacts != null) - contacts.PropagateVersion(this.Version); - - if(attendees != null) - attendees.PropagateVersion(this.Version); - - if(relatedTo != null) - relatedTo.PropagateVersion(this.Version); - - if(attachments != null) - attachments.PropagateVersion(this.Version); - - if(reqStats != null) - reqStats.PropagateVersion(this.Version); - - if(customProps != null) - customProps.PropagateVersion(this.Version); + contacts?.PropagateVersion(this.Version); + attendees?.PropagateVersion(this.Version); + relatedTo?.PropagateVersion(this.Version); + attachments?.PropagateVersion(this.Version); + reqStats?.PropagateVersion(this.Version); + customProps?.PropagateVersion(this.Version); base.PropagateVersion(); } @@ -582,8 +550,8 @@ public override void PropagateVersion() /// unique time zone IDs used by the calendar objects. public override void TimeZonesUsed(StringCollection timeZoneIds) { - CalendarObject.AddTimeZoneIfUsed(startDate, timeZoneIds); - CalendarObject.AddTimeZoneIfUsed(recurId, timeZoneIds); + AddTimeZoneIfUsed(startDate, timeZoneIds); + AddTimeZoneIfUsed(recurId, timeZoneIds); base.TimeZonesUsed(timeZoneIds); } @@ -594,10 +562,10 @@ public override void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public override void UpdateTimeZoneId(string oldId, string newId) + public override void UpdateTimeZoneId(string? oldId, string? newId) { - CalendarObject.UpdatePropertyTimeZoneId(startDate, oldId, newId); - CalendarObject.UpdatePropertyTimeZoneId(recurId, oldId, newId); + UpdatePropertyTimeZoneId(startDate, oldId, newId); + UpdatePropertyTimeZoneId(recurId, oldId, newId); base.UpdateTimeZoneId(oldId, newId); } @@ -609,10 +577,10 @@ public override void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public override void ApplyTimeZone(VTimeZone vTimeZone) + public override void ApplyTimeZone(VTimeZone? vTimeZone) { - CalendarObject.ApplyPropertyTimeZone(startDate, vTimeZone); - CalendarObject.ApplyPropertyTimeZone(recurId, vTimeZone); + ApplyPropertyTimeZone(startDate, vTimeZone); + ApplyPropertyTimeZone(recurId, vTimeZone); base.ApplyTimeZone(vTimeZone); } @@ -624,10 +592,10 @@ public override void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public override void SetTimeZone(VTimeZone vTimeZone) + public override void SetTimeZone(VTimeZone? vTimeZone) { - CalendarObject.SetPropertyTimeZone(startDate, vTimeZone); - CalendarObject.SetPropertyTimeZone(recurId, vTimeZone); + SetPropertyTimeZone(startDate, vTimeZone); + SetPropertyTimeZone(recurId, vTimeZone); base.SetTimeZone(vTimeZone); } @@ -640,7 +608,7 @@ public override void SetTimeZone(VTimeZone vTimeZone) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream. - public override void WriteToStream(TextWriter tw, StringBuilder sb) + public override void WriteToStream(TextWriter tw, StringBuilder? sb) { // DTSTAMP is always updated and written to reflect when the object was saved to the stream this.TimeStamp.DateTimeValue = DateTime.Now; @@ -668,30 +636,42 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(lastMod, sb, tw); if(contacts != null && contacts.Count != 0) + { foreach(ContactProperty c in contacts) BaseProperty.WriteToStream(c, sb, tw); + } if(attendees != null && attendees.Count != 0) + { foreach(AttendeeProperty a in attendees) BaseProperty.WriteToStream(a, sb, tw); + } if(relatedTo != null && relatedTo.Count != 0) + { foreach(RelatedToProperty r in relatedTo) BaseProperty.WriteToStream(r, sb, tw); + } if(reqStats != null && reqStats.Count != 0) + { foreach(RequestStatusProperty r in reqStats) BaseProperty.WriteToStream(r, sb, tw); + } base.WriteToStream(tw, sb); if(attachments != null && attachments.Count != 0) + { foreach(AttachProperty a in attachments) BaseProperty.WriteToStream(a, sb, tw); + } if(customProps != null && customProps.Count != 0) + { foreach(CustomProperty c in customProps) BaseProperty.WriteToStream(c, sb, tw); + } tw.Write("END:VJOURNAL\r\n"); } @@ -703,12 +683,12 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is VJournal j)) + if(obj is not VJournal j) return false; // The ToString() method returns a text representation of the journal based on all of its settings so // it's a reliable way to tell if two instances are the same. - return (this == j || this.ToString() == j.ToString()); + return this == j || this.ToString() == j.ToString(); } /// diff --git a/Source/EWSPDIData/PDIObjects/VJournalCollection.cs b/Source/EWSPDIData/PDIObjects/VJournalCollection.cs index d39b014..dd2b844 100644 --- a/Source/EWSPDIData/PDIObjects/VJournalCollection.cs +++ b/Source/EWSPDIData/PDIObjects/VJournalCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VJournalCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/06/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for VJournal objects // @@ -64,24 +63,28 @@ public VJournalCollection(IList journals) : base(journals) /// returned if it does not exist in the collection. /// This is thrown if an attempt is made to set an item using a /// unique ID that does not exist in the collection. - public VJournal this[string uniqueId] + public VJournal? this[string uniqueId] { get { for(int idx = 0; idx < base.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) return base[idx]; + } return null; } set { for(int idx = 0; idx < base.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) { - base[idx] = value; + base[idx] = value!; return; } + } throw new ArgumentException(LR.GetString("ExUIDNotFound")); } @@ -133,7 +136,7 @@ public void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public void UpdateTimeZoneId(string oldId, string newId) + public void UpdateTimeZoneId(string? oldId, string? newId) { foreach(VJournal j in this) j.UpdateTimeZoneId(oldId, newId); @@ -148,7 +151,7 @@ public void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public void ApplyTimeZone(VTimeZone vTimeZone) + public void ApplyTimeZone(VTimeZone? vTimeZone) { foreach(VJournal j in this) j.ApplyTimeZone(vTimeZone); @@ -163,7 +166,7 @@ public void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public void SetTimeZone(VTimeZone vTimeZone) + public void SetTimeZone(VTimeZone? vTimeZone) { foreach(VJournal j in this) j.SetTimeZone(vTimeZone); diff --git a/Source/EWSPDIData/PDIObjects/VNote.cs b/Source/EWSPDIData/PDIObjects/VNote.cs index d3f4786..96c6ae0 100644 --- a/Source/EWSPDIData/PDIObjects/VNote.cs +++ b/Source/EWSPDIData/PDIObjects/VNote.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VNote.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2013-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2013-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the vNote object // @@ -45,16 +44,16 @@ public class VNote : PDIObject, ISerializable //===================================================================== // Single vNote properties - private UniqueIdProperty uid; - private SummaryProperty summary; - private BodyProperty body; - private CategoriesProperty categories; - private ClassificationProperty classification; - private DateCreatedProperty dateCreated; - private LastModifiedProperty lastModified; + private UniqueIdProperty uid = null!; + private SummaryProperty summary = null!; + private BodyProperty body = null!; + private CategoriesProperty categories = null!; + private ClassificationProperty classification = null!; + private DateCreatedProperty dateCreated = null!; + private LastModifiedProperty lastModified = null!; // This is a catch-all that holds all unknown or extension properties - private CustomPropertyCollection customProps; + private CustomPropertyCollection customProps = null!; #endregion @@ -106,8 +105,7 @@ public SummaryProperty Summary { get { - if(summary == null) - summary = new SummaryProperty(); + summary ??= new SummaryProperty(); return summary; } @@ -120,8 +118,7 @@ public BodyProperty Body { get { - if(body == null) - body = new BodyProperty(); + body ??= new BodyProperty(); return body; } @@ -134,8 +131,7 @@ public CategoriesProperty Categories { get { - if(categories == null) - categories = new CategoriesProperty(); + categories ??= new CategoriesProperty(); return categories; } @@ -148,8 +144,7 @@ public ClassificationProperty Classification { get { - if(classification == null) - classification = new ClassificationProperty(); + classification ??= new ClassificationProperty(); return classification; } @@ -162,8 +157,7 @@ public DateCreatedProperty DateCreated { get { - if(dateCreated == null) - dateCreated = new DateCreatedProperty(); + dateCreated ??= new DateCreatedProperty(); return dateCreated; } @@ -176,8 +170,7 @@ public LastModifiedProperty LastModified { get { - if(lastModified == null) - lastModified = new LastModifiedProperty(); + lastModified ??= new LastModifiedProperty(); return lastModified; } @@ -191,8 +184,7 @@ public CustomPropertyCollection CustomProperties { get { - if(customProps == null) - customProps = new CustomPropertyCollection(); + customProps ??= []; return customProps; } @@ -240,8 +232,7 @@ protected VNote(SerializationInfo info, StreamingContext context) : this() [SecurityCritical] public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { - if(info != null) - info.AddValue("VNOTE", this.ToString()); + info?.AddValue("VNOTE", this.ToString()); } #endregion @@ -254,7 +245,7 @@ public virtual void GetObjectData(SerializationInfo info, StreamingContext conte /// A clone of the object public override object Clone() { - VNote o = new VNote(); + VNote o = new(); o.Clone(this); return o; } @@ -286,15 +277,15 @@ protected override void Clone(PDIObject p) /// public void ClearProperties() { - uid = null; - summary = null; - body = null; - classification = null; - categories = null; - dateCreated = null; - lastModified = null; - - customProps = null; + uid = null!; + summary = null!; + body = null!; + classification = null!; + categories = null!; + dateCreated = null!; + lastModified = null!; + + customProps = null!; } /// @@ -323,8 +314,7 @@ public void PropagateVersion() if(lastModified != null) lastModified.Version = this.Version; - if(customProps != null) - customProps.PropagateVersion(this.Version); + customProps?.PropagateVersion(this.Version); } /// @@ -334,12 +324,12 @@ public void PropagateVersion() /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is VNote vn)) + if(obj is not VNote vn) return false; // The ToString() method returns a text representation of the vNote based on all of its settings so // it's a reliable way to tell if two instances are the same. - return (this == vn || this.ToString() == vn.ToString()); + return this == vn || this.ToString() == vn.ToString(); } /// @@ -359,11 +349,10 @@ public override int GetHashCode() /// Returns a text description of the vNote suitable for saving to a PDI data stream public override string ToString() { - using(var sw = new StringWriter(new StringBuilder(1024), CultureInfo.InvariantCulture)) - { - this.WriteToStream(sw, null); - return sw.ToString(); - } + using var sw = new StringWriter(new StringBuilder(1024), CultureInfo.InvariantCulture); + + this.WriteToStream(sw, null); + return sw.ToString(); } /// @@ -413,7 +402,7 @@ public void WriteToStream(TextWriter tw) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they convert /// themselves to a string or write themselves to a PDI data stream. - public void WriteToStream(TextWriter tw, StringBuilder sb) + public void WriteToStream(TextWriter tw, StringBuilder? sb) { PropagateVersion(); @@ -436,8 +425,10 @@ public void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(lastModified, sb, tw); if(customProps != null && customProps.Count != 0) + { foreach(CustomProperty c in customProps) BaseProperty.WriteToStream(c, sb, tw); + } tw.Write("END:VNOTE\r\n"); } diff --git a/Source/EWSPDIData/PDIObjects/VNoteCollections.cs b/Source/EWSPDIData/PDIObjects/VNoteCollections.cs index 9fc25b1..52d0057 100644 --- a/Source/EWSPDIData/PDIObjects/VNoteCollections.cs +++ b/Source/EWSPDIData/PDIObjects/VNoteCollections.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VNoteCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/06/2014 -// Note : Copyright 2007-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2007-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for VNote objects // @@ -69,24 +68,28 @@ public VNoteCollection(IList notes) : base(notes) /// returned if it does not exist in the collection. /// This is thrown if an attempt is made to set an item using a /// unique ID that does not exist in the collection. - public VNote this[string uniqueId] + public VNote? this[string uniqueId] { get { for(int idx = 0; idx < base.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) return base[idx]; + } return null; } set { for(int idx = 0; idx < base.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) { - base[idx] = value; + base[idx] = value!; return; } + } throw new ArgumentException(LR.GetString("ExUIDNotFound")); } @@ -102,11 +105,10 @@ public VNote this[string uniqueId] /// A string containing the entire vNote collection public override string ToString() { - using(var sw = new StringWriter(new StringBuilder(4096), CultureInfo.InvariantCulture)) - { - this.WriteToStream(sw); - return sw.ToString(); - } + using var sw = new StringWriter(new StringBuilder(4096), CultureInfo.InvariantCulture); + + this.WriteToStream(sw); + return sw.ToString(); } /// @@ -149,9 +151,9 @@ public override string ToString() /// public void WriteToStream(TextWriter tw) { - StringBuilder sb = null; + StringBuilder? sb = null; - if(!(tw is StringWriter)) + if(tw is not StringWriter) sb = new StringBuilder(256); foreach(VNote n in this) diff --git a/Source/EWSPDIData/PDIObjects/VTimeZone.cs b/Source/EWSPDIData/PDIObjects/VTimeZone.cs index 42578a0..673057d 100644 --- a/Source/EWSPDIData/PDIObjects/VTimeZone.cs +++ b/Source/EWSPDIData/PDIObjects/VTimeZone.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VTimeZone.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the VTimeZone object used by vCalendar and iCalendar objects // @@ -40,16 +39,16 @@ public class VTimeZone : CalendarObject //===================================================================== // Single properties - private TimeZoneIdProperty timeZoneId; - private TimeZoneUrlProperty timeZoneUrl; - private LastModifiedProperty lastMod; + private TimeZoneIdProperty timeZoneId = null!; + private TimeZoneUrlProperty timeZoneUrl = null!; + private LastModifiedProperty lastMod = null!; // Time zone property collections. There can be one or more of each of these properties so they are // stored in a collection. - private ObservanceRuleCollection rules; + private ObservanceRuleCollection rules = null!; // This is a catch-all that holds all unknown or extension properties - private CustomPropertyCollection customProps; + private CustomPropertyCollection customProps = null!; #endregion @@ -86,8 +85,7 @@ public TimeZoneUrlProperty TimeZoneUrl { get { - if(timeZoneUrl == null) - timeZoneUrl = new TimeZoneUrlProperty(); + timeZoneUrl ??= new TimeZoneUrlProperty(); return timeZoneUrl; } @@ -100,8 +98,7 @@ public LastModifiedProperty LastModified { get { - if(lastMod == null) - lastMod = new LastModifiedProperty(); + lastMod ??= new LastModifiedProperty(); return lastMod; } @@ -115,8 +112,7 @@ public ObservanceRuleCollection ObservanceRules { get { - if(rules == null) - rules = new ObservanceRuleCollection(); + rules ??= []; return rules; } @@ -130,8 +126,7 @@ public CustomPropertyCollection CustomProperties { get { - if(customProps == null) - customProps = new CustomPropertyCollection(); + customProps ??= []; return customProps; } @@ -144,7 +139,7 @@ public CustomPropertyCollection CustomProperties /// /// This event is raised when the property is changed /// - public event EventHandler TimeZoneIdChanged; + public event EventHandler? TimeZoneIdChanged; /// /// This raises the event @@ -187,7 +182,7 @@ public VTimeZone() /// A clone of the object public override object Clone() { - VTimeZone o = new VTimeZone(); + VTimeZone o = new(); o.Clone(this); return o; } @@ -221,14 +216,14 @@ public override void ClearProperties() if(timeZoneId != null) { timeZoneId.TimeZoneIdChanged -= tzid_TimeZoneIdChanged; - timeZoneId = null; + timeZoneId = null!; } - timeZoneUrl = null; - lastMod = null; + timeZoneUrl = null!; + lastMod = null!; - rules = null; - customProps = null; + rules = null!; + customProps = null!; } /// @@ -245,11 +240,8 @@ public override void PropagateVersion() if(lastMod != null) lastMod.Version = this.Version; - if(rules != null) - rules.PropagateVersion(this.Version); - - if(customProps != null) - customProps.PropagateVersion(this.Version); + rules?.PropagateVersion(this.Version); + customProps?.PropagateVersion(this.Version); } /// @@ -266,7 +258,7 @@ public override void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public override void UpdateTimeZoneId(string oldId, string newId) + public override void UpdateTimeZoneId(string? oldId, string? newId) { } @@ -275,7 +267,7 @@ public override void UpdateTimeZoneId(string oldId, string newId) /// /// A object that will be used for all date/time objects /// in the component. - public override void ApplyTimeZone(VTimeZone vTimeZone) + public override void ApplyTimeZone(VTimeZone? vTimeZone) { } @@ -284,7 +276,7 @@ public override void ApplyTimeZone(VTimeZone vTimeZone) /// /// A object that will be used for all date/time objects /// in the component. - public override void SetTimeZone(VTimeZone vTimeZone) + public override void SetTimeZone(VTimeZone? vTimeZone) { } @@ -298,7 +290,7 @@ public override void SetTimeZone(VTimeZone vTimeZone) /// This is called by as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream. /// This is thrown if the TimeZoneId's Value property is null - public override void WriteToStream(TextWriter tw, StringBuilder sb) + public override void WriteToStream(TextWriter tw, StringBuilder? sb) { PropagateVersion(); @@ -313,12 +305,16 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(lastMod, sb, tw); if(rules != null && rules.Count != 0) + { foreach(ObservanceRule r in rules) r.WriteToStream(tw, sb); + } if(customProps != null && customProps.Count != 0) + { foreach(CustomProperty c in customProps) BaseProperty.WriteToStream(c, sb, tw); + } tw.Write("END:VTIMEZONE\r\n"); } @@ -330,12 +326,12 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is VTimeZone tz)) + if(obj is not VTimeZone tz) return false; // The ToString() method returns a text representation of the time zone based on all of its settings // so it's a reliable way to tell if two instances are the same. - return (this == tz || this.ToString() == tz.ToString()); + return this == tz || this.ToString() == tz.ToString(); } /// diff --git a/Source/EWSPDIData/PDIObjects/VTimeZoneCollection.cs b/Source/EWSPDIData/PDIObjects/VTimeZoneCollection.cs index c4565dd..d78cd4b 100644 --- a/Source/EWSPDIData/PDIObjects/VTimeZoneCollection.cs +++ b/Source/EWSPDIData/PDIObjects/VTimeZoneCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VTimeZoneCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/21/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for VTimeZone objects // @@ -44,9 +43,9 @@ public class VTimeZoneCollection : IList, ICollection, IEn //===================================================================== [NonSerialized] - private ReaderWriterLockSlim rwl; + private ReaderWriterLockSlim? rwl; - private List items; + private readonly List items; #endregion @@ -73,7 +72,7 @@ public class VTimeZoneCollection : IList, ICollection, IEn /// This event is raised when the value of a property of an item in /// the collection is changed. /// - public event EventHandler TimeZoneIdChanged; + public event EventHandler? TimeZoneIdChanged; /// /// This raises the event @@ -106,7 +105,7 @@ private void tzid_TimeZoneIdChanged(object sender, TimeZoneIdChangedEventArgs e) public VTimeZoneCollection() { this.MergingEnabled = true; - items = new List(); + items = []; } /// @@ -151,15 +150,17 @@ public int IndexOf(VTimeZone item) /// The time zone ID to find /// The zero-based index of the entry if it exists within the collection or -1 if it is not /// found. This version is much faster than the other version as it only has to compare ID values. - public int IndexOf(string tzid) + public int IndexOf(string? tzid) { this.AcquireReaderLock(250); try { for(int idx = 0; idx < items.Count; idx++) + { if(items[idx].TimeZoneId.Value == tzid) return idx; + } return -1; } @@ -179,7 +180,7 @@ public int IndexOf(string tzid) /// public void Insert(int index, VTimeZone item) { - VTimeZone existing = this[item.TimeZoneId.Value]; + VTimeZone? existing = this[item.TimeZoneId.Value]; if(existing == null) { @@ -275,7 +276,7 @@ public VTimeZone this[int index] /// is returned if it does not exist in the collection. /// This is thrown if an attempt is made to set an item using a time /// zone ID that does not exist in the collection. - public VTimeZone this[string timeZoneId] + public VTimeZone? this[string? timeZoneId] { get { @@ -284,8 +285,10 @@ public VTimeZone this[string timeZoneId] try { for(int idx = 0; idx < items.Count; idx++) + { if(items[idx].TimeZoneId.Value == timeZoneId) return items[idx]; + } return null; } @@ -298,14 +301,19 @@ public VTimeZone this[string timeZoneId] { this.AcquireWriterLock(250); + if(value == null) + throw new ArgumentNullException(nameof(value)); + try { for(int idx = 0; idx < items.Count; idx++) + { if(items[idx].TimeZoneId.Value == timeZoneId) { this[idx] = value; return; } + } throw new ArgumentException(LR.GetString("ExVTZIDNotFound")); } @@ -569,8 +577,8 @@ object IList.this[int index] /// The index at which to start copying void ICollection.CopyTo(Array array, int index) { - VTimeZone[] zones = array as VTimeZone[]; - this.CopyTo(zones, index); + if(array is VTimeZone[] zones) + this.CopyTo(zones, index); } /// @@ -616,12 +624,11 @@ public void AcquireReaderLock(int timeout, bool upgradeable = false) { lock(this.SyncRoot) { - if(rwl == null) - rwl = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + rwl ??= new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); } } - bool success = false; + bool success; if(upgradeable || rwl.IsUpgradeableReadLockHeld) success = rwl.TryEnterUpgradeableReadLock(timeout); @@ -638,11 +645,15 @@ public void AcquireReaderLock(int timeout, bool upgradeable = false) public void ReleaseReaderLock() { if(rwl != null) + { if(rwl.IsUpgradeableReadLockHeld) rwl.ExitUpgradeableReadLock(); else + { if(rwl.IsReadLockHeld) rwl.ExitReadLock(); + } + } } /// @@ -663,8 +674,7 @@ public void AcquireWriterLock(int timeout) { lock(this.SyncRoot) { - if(rwl == null) - rwl = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + rwl ??= new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); } } @@ -735,10 +745,7 @@ public ExtendedBindingList FindAll(Predicate match) { List foundItems = items.FindAll(match); - ExtendedBindingList collection = new ExtendedBindingList(); - - foreach(VTimeZone item in foundItems) - collection.Add(item); + ExtendedBindingList collection = [.. foundItems]; return collection; } @@ -1108,7 +1115,9 @@ public int Merge(VTimeZone vTimeZone) this.ReleaseWriterLock(); } } - else // Merge the rules if allowed + else + { + // Merge the rules if allowed if(this.MergingEnabled) { this.AcquireWriterLock(250); @@ -1120,8 +1129,10 @@ public int Merge(VTimeZone vTimeZone) foreach(ObservanceRule or in vTimeZone.ObservanceRules) { for(idx = 0; idx < rules.Count; idx++) + { if(rules[idx].Equals(or)) break; + } if(idx == rules.Count) rules.Add(or); @@ -1132,6 +1143,7 @@ public int Merge(VTimeZone vTimeZone) this.ReleaseWriterLock(); } } + } return tzIdx; } diff --git a/Source/EWSPDIData/PDIObjects/VToDo.cs b/Source/EWSPDIData/PDIObjects/VToDo.cs index bb4e2f8..3359f0e 100644 --- a/Source/EWSPDIData/PDIObjects/VToDo.cs +++ b/Source/EWSPDIData/PDIObjects/VToDo.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VToDo.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the definition for the VToDo object used by vCalendar and iCalendar objects // @@ -38,41 +37,41 @@ public class VToDo : RecurringObject //===================================================================== // Single to-do properties - private ClassificationProperty classification; - private CategoriesProperty categories; - private ResourcesProperty resources; - private UrlProperty url; - private UniqueIdProperty uid; - private GeographicPositionProperty geo; // iCalendar only - private LastModifiedProperty lastMod; - private DateCreatedProperty dateCreated; - private StartDateProperty startDate; - private DueDateProperty due; - private CompletedDateProperty completed; - private TimeStampProperty timeStamp; // iCalendar only - private SummaryProperty summary; - private DescriptionProperty desc; - private PriorityProperty priority; - private SequenceProperty sequence; - private RecurrenceCountProperty rNum; // vCalendar only - private CommentProperty comment; // iCalendar only - private OrganizerProperty organizer; // iCalendar only - private RecurrenceIdProperty recurId; // iCalendar only - private StatusProperty status; - private PercentCompleteProperty pct; // iCalendar only - private DurationProperty duration; // iCalendar only + private ClassificationProperty classification = null!; + private CategoriesProperty categories = null!; + private ResourcesProperty resources = null!; + private UrlProperty url = null!; + private UniqueIdProperty uid = null!; + private GeographicPositionProperty geo = null!; // iCalendar only + private LastModifiedProperty lastMod = null!; + private DateCreatedProperty dateCreated = null!; + private StartDateProperty startDate = null!; + private DueDateProperty due = null!; + private CompletedDateProperty completed = null!; + private TimeStampProperty timeStamp = null!; // iCalendar only + private SummaryProperty summary = null!; + private DescriptionProperty desc = null!; + private PriorityProperty priority = null!; + private SequenceProperty sequence = null!; + private RecurrenceCountProperty rNum = null!; // vCalendar only + private CommentProperty comment = null!; // iCalendar only + private OrganizerProperty organizer = null!; // iCalendar only + private RecurrenceIdProperty recurId = null!; // iCalendar only + private StatusProperty status = null!; + private PercentCompleteProperty pct = null!; // iCalendar only + private DurationProperty duration = null!; // iCalendar only // To-do property collections. There can be one or more of each of these properties so they are stored // in a collection. - private ContactPropertyCollection contacts; // iCalendar only - private AttendeePropertyCollection attendees; - private RelatedToPropertyCollection relatedTo; - private AttachPropertyCollection attachments; - private RequestStatusPropertyCollection reqStats; // iCalendar only - private VAlarmCollection alarms; + private ContactPropertyCollection contacts = null!; // iCalendar only + private AttendeePropertyCollection attendees = null!; + private RelatedToPropertyCollection relatedTo = null!; + private AttachPropertyCollection attachments = null!; + private RequestStatusPropertyCollection reqStats = null!; // iCalendar only + private VAlarmCollection alarms = null!; // This is a catch-all that holds all unknown or extension properties - private CustomPropertyCollection customProps; + private CustomPropertyCollection customProps = null!; #endregion @@ -93,8 +92,7 @@ public UrlProperty Url { get { - if(url == null) - url = new UrlProperty(); + url ??= new UrlProperty(); return url; } @@ -127,8 +125,7 @@ public LastModifiedProperty LastModified { get { - if(lastMod == null) - lastMod = new LastModifiedProperty(); + lastMod ??= new LastModifiedProperty(); return lastMod; } @@ -143,8 +140,7 @@ public GeographicPositionProperty GeographicPosition { get { - if(geo == null) - geo = new GeographicPositionProperty(); + geo ??= new GeographicPositionProperty(); return geo; } @@ -157,8 +153,7 @@ public ClassificationProperty Classification { get { - if(classification == null) - classification = new ClassificationProperty(); + classification ??= new ClassificationProperty(); return classification; } @@ -172,8 +167,7 @@ public CategoriesProperty Categories { get { - if(categories == null) - categories = new CategoriesProperty(); + categories ??= new CategoriesProperty(); return categories; } @@ -186,8 +180,7 @@ public ResourcesProperty Resources { get { - if(resources == null) - resources = new ResourcesProperty(); + resources ??= new ResourcesProperty(); return resources; } @@ -200,8 +193,7 @@ public DateCreatedProperty DateCreated { get { - if(dateCreated == null) - dateCreated = new DateCreatedProperty(); + dateCreated ??= new DateCreatedProperty(); return dateCreated; } @@ -217,8 +209,7 @@ public DueDateProperty DueDateTime { get { - if(due == null) - due = new DueDateProperty(); + due ??= new DueDateProperty(); return due; } @@ -231,8 +222,7 @@ public override StartDateProperty StartDateTime { get { - if(startDate == null) - startDate = new StartDateProperty(); + startDate ??= new StartDateProperty(); return startDate; } @@ -246,8 +236,7 @@ public CompletedDateProperty CompletedDateTime { get { - if(completed == null) - completed = new CompletedDateProperty(); + completed ??= new CompletedDateProperty(); return completed; } @@ -261,8 +250,7 @@ public TimeStampProperty TimeStamp { get { - if(timeStamp == null) - timeStamp = new TimeStampProperty { DateTimeValue = DateTime.Now }; + timeStamp ??= new TimeStampProperty { DateTimeValue = DateTime.Now }; return timeStamp; } @@ -275,8 +263,7 @@ public SummaryProperty Summary { get { - if(summary == null) - summary = new SummaryProperty(); + summary ??= new SummaryProperty(); return summary; } @@ -289,8 +276,7 @@ public DescriptionProperty Description { get { - if(desc == null) - desc = new DescriptionProperty(); + desc ??= new DescriptionProperty(); return desc; } @@ -303,8 +289,7 @@ public PriorityProperty Priority { get { - if(priority == null) - priority = new PriorityProperty(); + priority ??= new PriorityProperty(); return priority; } @@ -317,8 +302,7 @@ public SequenceProperty Sequence { get { - if(sequence == null) - sequence = new SequenceProperty(); + sequence ??= new SequenceProperty(); return sequence; } @@ -333,8 +317,7 @@ public RecurrenceCountProperty RecurrenceCount { get { - if(rNum == null) - rNum = new RecurrenceCountProperty(); + rNum ??= new RecurrenceCountProperty(); return rNum; } @@ -349,8 +332,7 @@ public CommentProperty Comment { get { - if(comment == null) - comment = new CommentProperty(); + comment ??= new CommentProperty(); return comment; } @@ -365,8 +347,7 @@ public OrganizerProperty Organizer { get { - if(organizer == null) - organizer = new OrganizerProperty(); + organizer ??= new OrganizerProperty(); return organizer; } @@ -381,8 +362,7 @@ public RecurrenceIdProperty RecurrenceId { get { - if(recurId == null) - recurId = new RecurrenceIdProperty(); + recurId ??= new RecurrenceIdProperty(); return recurId; } @@ -395,8 +375,7 @@ public StatusProperty Status { get { - if(status == null) - status = new StatusProperty(); + status ??= new StatusProperty(); return status; } @@ -412,8 +391,7 @@ public DurationProperty Duration { get { - if(duration == null) - duration = new DurationProperty(); + duration ??= new DurationProperty(); return duration; } @@ -426,8 +404,7 @@ public PercentCompleteProperty PercentComplete { get { - if(pct == null) - pct = new PercentCompleteProperty(); + pct ??= new PercentCompleteProperty(); return pct; } @@ -442,8 +419,7 @@ public ContactPropertyCollection Contacts { get { - if(contacts == null) - contacts = new ContactPropertyCollection(); + contacts ??= []; return contacts; } @@ -457,8 +433,7 @@ public AttendeePropertyCollection Attendees { get { - if(attendees == null) - attendees = new AttendeePropertyCollection(); + attendees ??= []; return attendees; } @@ -472,8 +447,7 @@ public RelatedToPropertyCollection RelatedTo { get { - if(relatedTo == null) - relatedTo = new RelatedToPropertyCollection(); + relatedTo ??= []; return relatedTo; } @@ -487,8 +461,7 @@ public AttachPropertyCollection Attachments { get { - if(attachments == null) - attachments = new AttachPropertyCollection(); + attachments ??= []; return attachments; } @@ -502,8 +475,7 @@ public RequestStatusPropertyCollection RequestStatuses { get { - if(reqStats == null) - reqStats = new RequestStatusPropertyCollection(); + reqStats ??= []; return reqStats; } @@ -521,8 +493,7 @@ public VAlarmCollection Alarms { get { - if(alarms == null) - alarms = new VAlarmCollection(); + alarms ??= []; return alarms; } @@ -537,8 +508,7 @@ public CustomPropertyCollection CustomProperties { get { - if(customProps == null) - customProps = new CustomPropertyCollection(); + customProps ??= []; return customProps; } @@ -559,7 +529,9 @@ public override Duration InstanceDuration { if((due == null || due.TimeZoneDateTime == DateTime.MinValue) && duration != null && duration.DurationValue != PDI.Duration.Zero) + { return duration.DurationValue; + } if(startDate != null && startDate.ValueLocation == ValLocValue.Date) return new Duration(TimeSpan.TicksPerDay); @@ -573,7 +545,7 @@ public override Duration InstanceDuration /// /// It returns the of the /// property. - public override string TimeZoneId => this.StartDateTime.TimeZoneId; + public override string? TimeZoneId => this.StartDateTime.TimeZoneId; #endregion @@ -599,7 +571,7 @@ public VToDo() /// A clone of the object public override object Clone() { - VToDo o = new VToDo(); + VToDo o = new(); o.Clone(this); return o; } @@ -655,38 +627,38 @@ protected override void Clone(PDIObject p) /// public override void ClearProperties() { - classification = null; - categories = null; - resources = null; - url = null; - uid = null; - geo = null; - lastMod = null; - dateCreated = null; - startDate = null; - due = null; - completed = null; - timeStamp = null; - summary = null; - desc = null; - priority = null; - sequence = null; - rNum = null; - comment = null; - organizer = null; - recurId = null; - status = null; - pct = null; - duration = null; - - contacts = null; - attendees = null; - relatedTo = null; - attachments = null; - reqStats = null; - alarms = null; - - customProps = null; + classification = null!; + categories = null!; + resources = null!; + url = null!; + uid = null!; + geo = null!; + lastMod = null!; + dateCreated = null!; + startDate = null!; + due = null!; + completed = null!; + timeStamp = null!; + summary = null!; + desc = null!; + priority = null!; + sequence = null!; + rNum = null!; + comment = null!; + organizer = null!; + recurId = null!; + status = null!; + pct = null!; + duration = null!; + + contacts = null!; + attendees = null!; + relatedTo = null!; + attachments = null!; + reqStats = null!; + alarms = null!; + + customProps = null!; base.ClearProperties(); } @@ -754,11 +726,8 @@ public override void PropagateVersion() if(duration != null) duration.Version = this.Version; - if(contacts != null) - contacts.PropagateVersion(this.Version); - - if(reqStats != null) - reqStats.PropagateVersion(this.Version); + contacts?.PropagateVersion(this.Version); + reqStats?.PropagateVersion(this.Version); } if(summary != null) @@ -776,20 +745,11 @@ public override void PropagateVersion() if(status != null) status.Version = this.Version; - if(attendees != null) - attendees.PropagateVersion(this.Version); - - if(relatedTo != null) - relatedTo.PropagateVersion(this.Version); - - if(attachments != null) - attachments.PropagateVersion(this.Version); - - if(alarms != null) - alarms.PropagateVersion(this.Version); - - if(customProps != null) - customProps.PropagateVersion(this.Version); + attendees?.PropagateVersion(this.Version); + relatedTo?.PropagateVersion(this.Version); + attachments?.PropagateVersion(this.Version); + alarms?.PropagateVersion(this.Version); + customProps?.PropagateVersion(this.Version); base.PropagateVersion(); } @@ -801,12 +761,11 @@ public override void PropagateVersion() /// unique time zone IDs used by the calendar objects. public override void TimeZonesUsed(StringCollection timeZoneIds) { - CalendarObject.AddTimeZoneIfUsed(startDate, timeZoneIds); - CalendarObject.AddTimeZoneIfUsed(due, timeZoneIds); - CalendarObject.AddTimeZoneIfUsed(recurId, timeZoneIds); + AddTimeZoneIfUsed(startDate, timeZoneIds); + AddTimeZoneIfUsed(due, timeZoneIds); + AddTimeZoneIfUsed(recurId, timeZoneIds); - if(alarms != null) - alarms.TimeZonesUsed(timeZoneIds); + alarms?.TimeZonesUsed(timeZoneIds); base.TimeZonesUsed(timeZoneIds); } @@ -817,14 +776,13 @@ public override void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public override void UpdateTimeZoneId(string oldId, string newId) + public override void UpdateTimeZoneId(string? oldId, string? newId) { - CalendarObject.UpdatePropertyTimeZoneId(startDate, oldId, newId); - CalendarObject.UpdatePropertyTimeZoneId(due, oldId, newId); - CalendarObject.UpdatePropertyTimeZoneId(recurId, oldId, newId); + UpdatePropertyTimeZoneId(startDate, oldId, newId); + UpdatePropertyTimeZoneId(due, oldId, newId); + UpdatePropertyTimeZoneId(recurId, oldId, newId); - if(alarms != null) - alarms.UpdateTimeZoneId(oldId, newId); + alarms?.UpdateTimeZoneId(oldId, newId); base.UpdateTimeZoneId(oldId, newId); } @@ -836,14 +794,13 @@ public override void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public override void ApplyTimeZone(VTimeZone vTimeZone) + public override void ApplyTimeZone(VTimeZone? vTimeZone) { - CalendarObject.ApplyPropertyTimeZone(startDate, vTimeZone); - CalendarObject.ApplyPropertyTimeZone(due, vTimeZone); - CalendarObject.ApplyPropertyTimeZone(recurId, vTimeZone); + ApplyPropertyTimeZone(startDate, vTimeZone); + ApplyPropertyTimeZone(due, vTimeZone); + ApplyPropertyTimeZone(recurId, vTimeZone); - if(alarms != null) - alarms.ApplyTimeZone(vTimeZone); + alarms?.ApplyTimeZone(vTimeZone); base.ApplyTimeZone(vTimeZone); } @@ -855,14 +812,13 @@ public override void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public override void SetTimeZone(VTimeZone vTimeZone) + public override void SetTimeZone(VTimeZone? vTimeZone) { - CalendarObject.SetPropertyTimeZone(startDate, vTimeZone); - CalendarObject.SetPropertyTimeZone(due, vTimeZone); - CalendarObject.SetPropertyTimeZone(recurId, vTimeZone); + SetPropertyTimeZone(startDate, vTimeZone); + SetPropertyTimeZone(due, vTimeZone); + SetPropertyTimeZone(recurId, vTimeZone); - if(alarms != null) - alarms.SetTimeZone(vTimeZone); + alarms?.SetTimeZone(vTimeZone); base.SetTimeZone(vTimeZone); } @@ -876,7 +832,7 @@ public override void SetTimeZone(VTimeZone vTimeZone) /// buffer. This can be null if the TextWriter is a . /// This is called by as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream. - public override void WriteToStream(TextWriter tw, StringBuilder sb) + public override void WriteToStream(TextWriter tw, StringBuilder? sb) { // DTSTAMP is always updated and written to reflect when the object was saved to the stream // (iCalendar 2.0 only). @@ -899,7 +855,9 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) // Duration and due date are mutually exclusive. If there is a due date, duration is ignored. if((due == null || due.TimeZoneDateTime == DateTime.MinValue) && duration != null && duration.DurationValue != PDI.Duration.Zero) + { BaseProperty.WriteToStream(duration, sb, tw); + } BaseProperty.WriteToStream(pct, sb, tw); } @@ -918,12 +876,16 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(recurId, sb, tw); if(contacts != null && contacts.Count != 0) + { foreach(ContactProperty c in contacts) BaseProperty.WriteToStream(c, sb, tw); + } if(reqStats != null && reqStats.Count != 0) + { foreach(RequestStatusProperty r in reqStats) BaseProperty.WriteToStream(r, sb, tw); + } } BaseProperty.WriteToStream(classification, sb, tw); @@ -937,26 +899,36 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) BaseProperty.WriteToStream(lastMod, sb, tw); if(attendees != null && attendees.Count != 0) + { foreach(AttendeeProperty a in attendees) BaseProperty.WriteToStream(a, sb, tw); + } if(relatedTo != null && relatedTo.Count != 0) + { foreach(RelatedToProperty r in relatedTo) BaseProperty.WriteToStream(r, sb, tw); + } base.WriteToStream(tw, sb); if(alarms != null && alarms.Count != 0) + { foreach(VAlarm a in alarms) a.WriteToStream(tw, sb); + } if(attachments != null && attachments.Count != 0) + { foreach(AttachProperty a in attachments) BaseProperty.WriteToStream(a, sb, tw); + } if(customProps != null && customProps.Count != 0) + { foreach(CustomProperty c in customProps) BaseProperty.WriteToStream(c, sb, tw); + } tw.Write("END:VTODO\r\n"); } @@ -968,12 +940,12 @@ public override void WriteToStream(TextWriter tw, StringBuilder sb) /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is VToDo td)) + if(obj is not VToDo td) return false; // The ToString() method returns a text representation of the object based on all of its settings so // it's a reliable way to tell if two instances are the same. - return (this == td || this.ToString() == td.ToString()); + return this == td || this.ToString() == td.ToString(); } /// diff --git a/Source/EWSPDIData/PDIObjects/VToDoCollection.cs b/Source/EWSPDIData/PDIObjects/VToDoCollection.cs index 0728dac..05b607e 100644 --- a/Source/EWSPDIData/PDIObjects/VToDoCollection.cs +++ b/Source/EWSPDIData/PDIObjects/VToDoCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VToDoCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/13/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for VToDo objects // @@ -64,24 +63,28 @@ public VToDoCollection(IList todos) : base(todos) /// returned if it does not exist in the collection. /// This is thrown if an attempt is made to set an item using a /// unique ID that does not exist in the collection. - public VToDo this[string uniqueId] + public VToDo? this[string uniqueId] { get { for(int idx = 0; idx < base.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) return base[idx]; + } return null; } set { for(int idx = 0; idx < base.Count; idx++) + { if(base[idx].UniqueId.Value == uniqueId) { - base[idx] = value; + base[idx] = value!; return; } + } throw new ArgumentException(LR.GetString("ExUIDNotFound")); } @@ -133,7 +136,7 @@ public void TimeZonesUsed(StringCollection timeZoneIds) /// /// The old ID being replaced /// The new ID to use - public void UpdateTimeZoneId(string oldId, string newId) + public void UpdateTimeZoneId(string? oldId, string? newId) { foreach(VToDo t in this) t.UpdateTimeZoneId(oldId, newId); @@ -148,7 +151,7 @@ public void UpdateTimeZoneId(string oldId, string newId) /// A object that will be used for all date/time objects /// in the component. /// When applied, all date/time values in the object will be converted to the new time zone - public void ApplyTimeZone(VTimeZone vTimeZone) + public void ApplyTimeZone(VTimeZone? vTimeZone) { foreach(VToDo t in this) t.ApplyTimeZone(vTimeZone); @@ -163,7 +166,7 @@ public void ApplyTimeZone(VTimeZone vTimeZone) /// A object that will be used for all date/time objects /// in the component. /// This method does not affect the date/time values - public void SetTimeZone(VTimeZone vTimeZone) + public void SetTimeZone(VTimeZone? vTimeZone) { foreach(VToDo t in this) t.SetTimeZone(vTimeZone); diff --git a/Source/EWSPDIData/PDIParser/PDIParser.cs b/Source/EWSPDIData/PDIParser/PDIParser.cs index 769e6c4..901dbcb 100644 --- a/Source/EWSPDIData/PDIParser/PDIParser.cs +++ b/Source/EWSPDIData/PDIParser/PDIParser.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : PDIParser.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a class used to parse Personal Data Interchange (PDI) data streams containing vCalendar, // iCalendar, and vCard objects. @@ -75,12 +74,12 @@ protected enum ParserState private ParserState state; // Current parser state - private StringBuilder sb; // The parsing buffer + private readonly StringBuilder sb; // The parsing buffer - private string propertyName; // The property name + private string propertyName = null!; // The property name // The string collection of parameters. It's re-used to save resources - private StringCollection propParams; + private readonly StringCollection propParams; #endregion @@ -115,7 +114,7 @@ protected enum ParserState protected PDIParser() { sb = new StringBuilder(100); - propParams = new StringCollection(); + propParams = []; } #endregion @@ -311,24 +310,22 @@ private void ProcessCharacter(char ch) /// private void ProcessParameters() { - string[] parameters = null; - // Null characters terminate each parameter name and value in the string builder so we can split on // them. propParams.Clear(); if(sb.Length > 0) { - parameters = sb.ToString().Split('\x0'); + var parameters = sb.ToString().Split('\x0'); // Look for a QUOTED-PRINTABLE parameter value. If present, the upcoming value is encoded that // way and may contain soft line breaks that require us to unfold the lines. - for(int nIdx = 0; nIdx < parameters.Length; nIdx++) + for(int idx = 0; idx < parameters.Length; idx++) { - if(String.Compare(parameters[nIdx], EncodingValue.QuotedPrintable, StringComparison.OrdinalIgnoreCase) == 0) + if(String.Compare(parameters[idx], EncodingValue.QuotedPrintable, StringComparison.OrdinalIgnoreCase) == 0) isQPValue = true; - propParams.Add(parameters[nIdx]); + propParams.Add(parameters[idx]); } } @@ -395,7 +392,7 @@ protected void Flush() /// Dim vCards As VCardCollection = vcp.VCards /// /// - public void ParseString(string pdiText) + public void ParseString(string? pdiText) { // Ignore it if there is nothing to parse if(pdiText == null || pdiText.Length == 0) @@ -403,10 +400,9 @@ public void ParseString(string pdiText) // We could parse it here for speed, but the code would be identical to the TextReader version below // so we'll save some code maintenance and wrap it in a StringReader. - using(var sr = new StringReader(pdiText)) - { - this.ParseReader(sr); - } + using var sr = new StringReader(pdiText); + + this.ParseReader(sr); } /// @@ -502,8 +498,7 @@ public void ParseReader(TextReader tr) { // We should be in the property value except if just starting if(lineNbr > 0 && state != ParserState.PropertyValue) - throw new PDIParserException(lineNbr, - LR.GetString("ExParseSepNotFound")); + throw new PDIParserException(lineNbr, LR.GetString("ExParseSepNotFound")); this.ProcessCharacter('\n'); } @@ -520,6 +515,7 @@ public void ParseReader(TextReader tr) isUnfolding = true; } else + { if(ch == '\n') { isStartOfLine = true; // End of line @@ -528,6 +524,7 @@ public void ParseReader(TextReader tr) } else // Continuing current line this.ProcessCharacter(ch); + } } } @@ -577,7 +574,7 @@ public void ParseReader(TextReader tr) /// public void ParseFile(string filename) { - StreamReader sr = null; + StreamReader? sr = null; if(filename == null || filename.Length == 0) throw new ArgumentNullException(nameof(filename), LR.GetString("ExParseNoFilename")); @@ -593,6 +590,7 @@ public void ParseFile(string filename) sr = new StreamReader(wrsp.GetResponseStream(), DefaultEncoding); } else + { if(filename.StartsWith("file:", StringComparison.OrdinalIgnoreCase)) { FileWebRequest frq = (FileWebRequest)WebRequest.Create(new Uri(filename)); @@ -601,6 +599,7 @@ public void ParseFile(string filename) } else sr = new StreamReader(filename, DefaultEncoding); + } this.ParseReader(sr); } @@ -616,8 +615,7 @@ public void ParseFile(string filename) } finally { - if(sr != null) - sr.Close(); + sr?.Close(); } } #endregion diff --git a/Source/EWSPDIData/PDIParser/VCalendarParser.cs b/Source/EWSPDIData/PDIParser/VCalendarParser.cs index 0c30073..f9f3500 100644 --- a/Source/EWSPDIData/PDIParser/VCalendarParser.cs +++ b/Source/EWSPDIData/PDIParser/VCalendarParser.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VCalendarParser.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a class used to parse vCalendar and iCalendar Personal Data Interchange (PDI) data streams. // It supports both the vCalendar 1.0 and iCalendar 2.0 specification file formats. @@ -69,256 +68,265 @@ protected enum VCalendarParserState #region Private data members //===================================================================== - private VCalendar vCal; // The vCalendar/iCalendar being processed - private VEvent vEvent; // The event item being processed - private VToDo vToDo; // The to-do item being processed - private VJournal vJournal; // The journal item being processed - private VAlarm vAlarm; // The alarm item being processed - private VFreeBusy vFreeBusy; // The free/busy item being processed - private VTimeZone vTimeZone; // The time zone being processed - private ObservanceRule obsRule; // The observance rule being processed + private VCalendar? vCal; // The vCalendar/iCalendar being processed + private VEvent? vEvent; // The event item being processed + private VToDo? vToDo; // The to-do item being processed + private VJournal? vJournal; // The journal item being processed + private VAlarm? vAlarm; // The alarm item being processed + private VFreeBusy? vFreeBusy; // The free/busy item being processed + private VTimeZone? vTimeZone; // The time zone being processed + private ObservanceRule? obsRule; // The observance rule being processed // The current calendar parser state private VCalendarParserState currentState; // Prior states - private Stack priorState; - private Stack beginValue; + private readonly Stack priorState; + private readonly Stack beginValue; //===================================================================== // These private arrays are used to translate property names into property types // The calendar overall - private static NameToValue[] ntvCal = { - new NameToValue("BEGIN", PropertyType.Begin), - new NameToValue("END", PropertyType.End), - new NameToValue("VERSION", PropertyType.Version), - new NameToValue("PRODID", PropertyType.ProductId), - new NameToValue("CALSCALE", PropertyType.CalendarScale), - new NameToValue("METHOD", PropertyType.Method), - new NameToValue("GEO", PropertyType.GeographicPosition), - new NameToValue("TZ", PropertyType.TimeZone), - new NameToValue("DAYLIGHT", PropertyType.Daylight), + private static readonly NameToValue[] ntvCal = + [ + new("BEGIN", PropertyType.Begin), + new("END", PropertyType.End), + new("VERSION", PropertyType.Version), + new("PRODID", PropertyType.ProductId), + new("CALSCALE", PropertyType.CalendarScale), + new("METHOD", PropertyType.Method), + new("GEO", PropertyType.GeographicPosition), + new("TZ", PropertyType.TimeZone), + new("DAYLIGHT", PropertyType.Daylight), // The last entry should always be CustomProperty to catch all unrecognized properties. The actual // property name is not relevant. - new NameToValue("X-", PropertyType.Custom) - }; + new("X-", PropertyType.Custom) + ]; // The calendar objects - private static NameToValue[] ntvObjs = { - new NameToValue("VCALENDAR", VCalendarParserState.VCalendar), - new NameToValue("VEVENT", VCalendarParserState.VEvent), - new NameToValue("VTODO", VCalendarParserState.VToDo), - new NameToValue("VJOURNAL", VCalendarParserState.VJournal), - new NameToValue("VFREEBUSY", VCalendarParserState.VFreeBusy), - new NameToValue("VTIMEZONE", VCalendarParserState.VTimeZone), + private static readonly NameToValue[] ntvObjs = + [ + new("VCALENDAR", VCalendarParserState.VCalendar), + new("VEVENT", VCalendarParserState.VEvent), + new("VTODO", VCalendarParserState.VToDo), + new("VJOURNAL", VCalendarParserState.VJournal), + new("VFREEBUSY", VCalendarParserState.VFreeBusy), + new("VTIMEZONE", VCalendarParserState.VTimeZone), // The last entry should always be custom to catch all unrecognized objects. The actual property // name is not relevant. - new NameToValue("X-", VCalendarParserState.Custom) - }; + new("X-", VCalendarParserState.Custom) + ]; // Event items - private static NameToValue[] ntvEvent = { - new NameToValue("BEGIN", PropertyType.Begin), - new NameToValue("END", PropertyType.End), - new NameToValue("CLASS", PropertyType.Class), - new NameToValue("CATEGORIES", PropertyType.Categories), - new NameToValue("RESOURCES", PropertyType.Resources), - new NameToValue("URL", PropertyType.Url), - new NameToValue("UID", PropertyType.UniqueId), - new NameToValue("LAST-MODIFIED", PropertyType.LastModified), - new NameToValue("GEO", PropertyType.GeographicPosition), - new NameToValue("DCREATED", PropertyType.DateCreated), - new NameToValue("CREATED", PropertyType.DateCreated), - new NameToValue("DTSTART", PropertyType.StartDateTime), - new NameToValue("DTEND", PropertyType.EndDateTime), - new NameToValue("DTSTAMP", PropertyType.TimeStamp), - new NameToValue("SUMMARY", PropertyType.Summary), - new NameToValue("DESCRIPTION", PropertyType.Description), - new NameToValue("LOCATION", PropertyType.Location), - new NameToValue("PRIORITY", PropertyType.Priority), - new NameToValue("SEQUENCE", PropertyType.Sequence), - new NameToValue("TRANSP", PropertyType.Transparency), - new NameToValue("RNUM", PropertyType.RecurrenceCount), - new NameToValue("COMMENT", PropertyType.Comment), - new NameToValue("CONTACT", PropertyType.Contact), - new NameToValue("ORGANIZER", PropertyType.Organizer), - new NameToValue("ATTENDEE", PropertyType.Attendee), - new NameToValue("RELATED-TO", PropertyType.RelatedTo), - new NameToValue("ATTACH", PropertyType.Attachment), - new NameToValue("RECURRENCE-ID", PropertyType.RecurrenceId), - new NameToValue("STATUS", PropertyType.Status), - new NameToValue("REQUEST-STATUS", PropertyType.RequestStatus), - new NameToValue("DURATION", PropertyType.Duration), - new NameToValue("AALARM", PropertyType.AudioAlarm), - new NameToValue("DALARM", PropertyType.DisplayAlarm), - new NameToValue("MALARM", PropertyType.EMailAlarm), - new NameToValue("PALARM", PropertyType.ProcedureAlarm), - new NameToValue("RRULE", PropertyType.RecurrenceRule), - new NameToValue("RDATE", PropertyType.RecurDate), - new NameToValue("EXRULE", PropertyType.ExceptionRule), - new NameToValue("EXDATE", PropertyType.ExceptionDate), - new NameToValue("X-EWSOFTWARE-EXCLUDESTART", PropertyType.ExcludeStartDateTime), + private static readonly NameToValue[] ntvEvent = + [ + new("BEGIN", PropertyType.Begin), + new("END", PropertyType.End), + new("CLASS", PropertyType.Class), + new("CATEGORIES", PropertyType.Categories), + new("RESOURCES", PropertyType.Resources), + new("URL", PropertyType.Url), + new("UID", PropertyType.UniqueId), + new("LAST-MODIFIED", PropertyType.LastModified), + new("GEO", PropertyType.GeographicPosition), + new("DCREATED", PropertyType.DateCreated), + new("CREATED", PropertyType.DateCreated), + new("DTSTART", PropertyType.StartDateTime), + new("DTEND", PropertyType.EndDateTime), + new("DTSTAMP", PropertyType.TimeStamp), + new("SUMMARY", PropertyType.Summary), + new("DESCRIPTION", PropertyType.Description), + new("LOCATION", PropertyType.Location), + new("PRIORITY", PropertyType.Priority), + new("SEQUENCE", PropertyType.Sequence), + new("TRANSP", PropertyType.Transparency), + new("RNUM", PropertyType.RecurrenceCount), + new("COMMENT", PropertyType.Comment), + new("CONTACT", PropertyType.Contact), + new("ORGANIZER", PropertyType.Organizer), + new("ATTENDEE", PropertyType.Attendee), + new("RELATED-TO", PropertyType.RelatedTo), + new("ATTACH", PropertyType.Attachment), + new("RECURRENCE-ID", PropertyType.RecurrenceId), + new("STATUS", PropertyType.Status), + new("REQUEST-STATUS", PropertyType.RequestStatus), + new("DURATION", PropertyType.Duration), + new("AALARM", PropertyType.AudioAlarm), + new("DALARM", PropertyType.DisplayAlarm), + new("MALARM", PropertyType.EMailAlarm), + new("PALARM", PropertyType.ProcedureAlarm), + new("RRULE", PropertyType.RecurrenceRule), + new("RDATE", PropertyType.RecurDate), + new("EXRULE", PropertyType.ExceptionRule), + new("EXDATE", PropertyType.ExceptionDate), + new("X-EWSOFTWARE-EXCLUDESTART", PropertyType.ExcludeStartDateTime), // The last entry should always be CustomProperty to catch all unrecognized properties. The actual // property name is not relevant. - new NameToValue("X-", PropertyType.Custom) - }; + new("X-", PropertyType.Custom) + ]; // To-Do items - private static NameToValue[] ntvToDo = { - new NameToValue("BEGIN", PropertyType.Begin), - new NameToValue("END", PropertyType.End), - new NameToValue("CLASS", PropertyType.Class), - new NameToValue("CATEGORIES", PropertyType.Categories), - new NameToValue("RESOURCES", PropertyType.Resources), - new NameToValue("URL", PropertyType.Url), - new NameToValue("UID", PropertyType.UniqueId), - new NameToValue("LAST-MODIFIED", PropertyType.LastModified), - new NameToValue("GEO", PropertyType.GeographicPosition), - new NameToValue("DCREATED", PropertyType.DateCreated), - new NameToValue("CREATED", PropertyType.DateCreated), - new NameToValue("DUE", PropertyType.DueDate), - new NameToValue("DTSTART", PropertyType.StartDateTime), - new NameToValue("COMPLETED", PropertyType.CompletedDate), - new NameToValue("DTSTAMP", PropertyType.TimeStamp), - new NameToValue("SUMMARY", PropertyType.Summary), - new NameToValue("DESCRIPTION", PropertyType.Description), - new NameToValue("PRIORITY", PropertyType.Priority), - new NameToValue("SEQUENCE", PropertyType.Sequence), - new NameToValue("RNUM", PropertyType.RecurrenceCount), - new NameToValue("COMMENT", PropertyType.Comment), - new NameToValue("CONTACT", PropertyType.Contact), - new NameToValue("ORGANIZER", PropertyType.Organizer), - new NameToValue("ATTENDEE", PropertyType.Attendee), - new NameToValue("RELATED-TO", PropertyType.RelatedTo), - new NameToValue("ATTACH", PropertyType.Attachment), - new NameToValue("RECURRENCE-ID", PropertyType.RecurrenceId), - new NameToValue("STATUS", PropertyType.Status), - new NameToValue("REQUEST-STATUS", PropertyType.RequestStatus), - new NameToValue("PERCENT-COMPLETE", PropertyType.PercentComplete), - new NameToValue("DURATION", PropertyType.Duration), - new NameToValue("AALARM", PropertyType.AudioAlarm), - new NameToValue("DALARM", PropertyType.DisplayAlarm), - new NameToValue("MALARM", PropertyType.EMailAlarm), - new NameToValue("PALARM", PropertyType.ProcedureAlarm), - new NameToValue("RRULE", PropertyType.RecurrenceRule), - new NameToValue("RDATE", PropertyType.RecurDate), - new NameToValue("EXRULE", PropertyType.ExceptionRule), - new NameToValue("EXDATE", PropertyType.ExceptionDate), - new NameToValue("X-EWSOFTWARE-EXCLUDESTART", PropertyType.ExcludeStartDateTime), + private static readonly NameToValue[] ntvToDo = + [ + new("BEGIN", PropertyType.Begin), + new("END", PropertyType.End), + new("CLASS", PropertyType.Class), + new("CATEGORIES", PropertyType.Categories), + new("RESOURCES", PropertyType.Resources), + new("URL", PropertyType.Url), + new("UID", PropertyType.UniqueId), + new("LAST-MODIFIED", PropertyType.LastModified), + new("GEO", PropertyType.GeographicPosition), + new("DCREATED", PropertyType.DateCreated), + new("CREATED", PropertyType.DateCreated), + new("DUE", PropertyType.DueDate), + new("DTSTART", PropertyType.StartDateTime), + new("COMPLETED", PropertyType.CompletedDate), + new("DTSTAMP", PropertyType.TimeStamp), + new("SUMMARY", PropertyType.Summary), + new("DESCRIPTION", PropertyType.Description), + new("PRIORITY", PropertyType.Priority), + new("SEQUENCE", PropertyType.Sequence), + new("RNUM", PropertyType.RecurrenceCount), + new("COMMENT", PropertyType.Comment), + new("CONTACT", PropertyType.Contact), + new("ORGANIZER", PropertyType.Organizer), + new("ATTENDEE", PropertyType.Attendee), + new("RELATED-TO", PropertyType.RelatedTo), + new("ATTACH", PropertyType.Attachment), + new("RECURRENCE-ID", PropertyType.RecurrenceId), + new("STATUS", PropertyType.Status), + new("REQUEST-STATUS", PropertyType.RequestStatus), + new("PERCENT-COMPLETE", PropertyType.PercentComplete), + new("DURATION", PropertyType.Duration), + new("AALARM", PropertyType.AudioAlarm), + new("DALARM", PropertyType.DisplayAlarm), + new("MALARM", PropertyType.EMailAlarm), + new("PALARM", PropertyType.ProcedureAlarm), + new("RRULE", PropertyType.RecurrenceRule), + new("RDATE", PropertyType.RecurDate), + new("EXRULE", PropertyType.ExceptionRule), + new("EXDATE", PropertyType.ExceptionDate), + new("X-EWSOFTWARE-EXCLUDESTART", PropertyType.ExcludeStartDateTime), // The last entry should always be CustomProperty to catch all unrecognized properties. The actual // property name is not relevant. - new NameToValue("X-", PropertyType.Custom) - }; + new("X-", PropertyType.Custom) + ]; // Journal items - private static NameToValue[] ntvJournal = { - new NameToValue("BEGIN", PropertyType.Begin), - new NameToValue("END", PropertyType.End), - new NameToValue("CLASS", PropertyType.Class), - new NameToValue("CATEGORIES", PropertyType.Categories), - new NameToValue("URL", PropertyType.Url), - new NameToValue("UID", PropertyType.UniqueId), - new NameToValue("LAST-MODIFIED", PropertyType.LastModified), - new NameToValue("CREATED", PropertyType.DateCreated), - new NameToValue("DTSTART", PropertyType.StartDateTime), - new NameToValue("DTSTAMP", PropertyType.TimeStamp), - new NameToValue("SUMMARY", PropertyType.Summary), - new NameToValue("DESCRIPTION", PropertyType.Description), - new NameToValue("SEQUENCE", PropertyType.Sequence), - new NameToValue("COMMENT", PropertyType.Comment), - new NameToValue("CONTACT", PropertyType.Contact), - new NameToValue("ORGANIZER", PropertyType.Organizer), - new NameToValue("ATTENDEE", PropertyType.Attendee), - new NameToValue("RELATED-TO", PropertyType.RelatedTo), - new NameToValue("ATTACH", PropertyType.Attachment), - new NameToValue("RECURRENCE-ID", PropertyType.RecurrenceId), - new NameToValue("STATUS", PropertyType.Status), - new NameToValue("REQUEST-STATUS", PropertyType.RequestStatus), - new NameToValue("RRULE", PropertyType.RecurrenceRule), - new NameToValue("RDATE", PropertyType.RecurDate), - new NameToValue("EXRULE", PropertyType.ExceptionRule), - new NameToValue("EXDATE", PropertyType.ExceptionDate), - new NameToValue("X-EWSOFTWARE-EXCLUDESTART", PropertyType.ExcludeStartDateTime), + private static readonly NameToValue[] ntvJournal = + [ + new("BEGIN", PropertyType.Begin), + new("END", PropertyType.End), + new("CLASS", PropertyType.Class), + new("CATEGORIES", PropertyType.Categories), + new("URL", PropertyType.Url), + new("UID", PropertyType.UniqueId), + new("LAST-MODIFIED", PropertyType.LastModified), + new("CREATED", PropertyType.DateCreated), + new("DTSTART", PropertyType.StartDateTime), + new("DTSTAMP", PropertyType.TimeStamp), + new("SUMMARY", PropertyType.Summary), + new("DESCRIPTION", PropertyType.Description), + new("SEQUENCE", PropertyType.Sequence), + new("COMMENT", PropertyType.Comment), + new("CONTACT", PropertyType.Contact), + new("ORGANIZER", PropertyType.Organizer), + new("ATTENDEE", PropertyType.Attendee), + new("RELATED-TO", PropertyType.RelatedTo), + new("ATTACH", PropertyType.Attachment), + new("RECURRENCE-ID", PropertyType.RecurrenceId), + new("STATUS", PropertyType.Status), + new("REQUEST-STATUS", PropertyType.RequestStatus), + new("RRULE", PropertyType.RecurrenceRule), + new("RDATE", PropertyType.RecurDate), + new("EXRULE", PropertyType.ExceptionRule), + new("EXDATE", PropertyType.ExceptionDate), + new("X-EWSOFTWARE-EXCLUDESTART", PropertyType.ExcludeStartDateTime), // The last entry should always be CustomProperty to catch all unrecognized properties. The actual // property name is not relevant. - new NameToValue("X-", PropertyType.Custom) - }; + new("X-", PropertyType.Custom) + ]; // VAlarm items - private static NameToValue[] ntvAlarm = { - new NameToValue("BEGIN", PropertyType.Begin), - new NameToValue("END", PropertyType.End), - new NameToValue("ACTION", PropertyType.Action), - new NameToValue("TRIGGER", PropertyType.Trigger), - new NameToValue("REPEAT", PropertyType.Repeat), - new NameToValue("DURATION", PropertyType.Duration), - new NameToValue("SUMMARY", PropertyType.Summary), - new NameToValue("DESCRIPTION", PropertyType.Description), - new NameToValue("ATTACH", PropertyType.Attachment), - new NameToValue("ATTENDEE", PropertyType.Attendee), + private static readonly NameToValue[] ntvAlarm = + [ + new("BEGIN", PropertyType.Begin), + new("END", PropertyType.End), + new("ACTION", PropertyType.Action), + new("TRIGGER", PropertyType.Trigger), + new("REPEAT", PropertyType.Repeat), + new("DURATION", PropertyType.Duration), + new("SUMMARY", PropertyType.Summary), + new("DESCRIPTION", PropertyType.Description), + new("ATTACH", PropertyType.Attachment), + new("ATTENDEE", PropertyType.Attendee), // The last entry should always be CustomProperty to catch all unrecognized properties. The actual // property name is not relevant. - new NameToValue("X-", PropertyType.Custom) - }; + new("X-", PropertyType.Custom) + ]; // Free/Busy items - private static NameToValue[] ntvFreeBusy = { - new NameToValue("BEGIN", PropertyType.Begin), - new NameToValue("END", PropertyType.End), - new NameToValue("URL", PropertyType.Url), - new NameToValue("UID", PropertyType.UniqueId), - new NameToValue("DTSTART", PropertyType.StartDateTime), - new NameToValue("DTEND", PropertyType.EndDateTime), - new NameToValue("DURATION", PropertyType.Duration), - new NameToValue("DTSTAMP", PropertyType.TimeStamp), - new NameToValue("COMMENT", PropertyType.Comment), - new NameToValue("CONTACT", PropertyType.Contact), - new NameToValue("ORGANIZER", PropertyType.Organizer), - new NameToValue("ATTENDEE", PropertyType.Attendee), - new NameToValue("REQUEST-STATUS", PropertyType.RequestStatus), - new NameToValue("FREEBUSY", PropertyType.FreeBusy), + private static readonly NameToValue[] ntvFreeBusy = + [ + new("BEGIN", PropertyType.Begin), + new("END", PropertyType.End), + new("URL", PropertyType.Url), + new("UID", PropertyType.UniqueId), + new("DTSTART", PropertyType.StartDateTime), + new("DTEND", PropertyType.EndDateTime), + new("DURATION", PropertyType.Duration), + new("DTSTAMP", PropertyType.TimeStamp), + new("COMMENT", PropertyType.Comment), + new("CONTACT", PropertyType.Contact), + new("ORGANIZER", PropertyType.Organizer), + new("ATTENDEE", PropertyType.Attendee), + new("REQUEST-STATUS", PropertyType.RequestStatus), + new("FREEBUSY", PropertyType.FreeBusy), // The last entry should always be CustomProperty to catch all unrecognized properties. The actual // property name is not relevant. - new NameToValue("X-", PropertyType.Custom) - }; + new("X-", PropertyType.Custom) + ]; // Time Zone items - private static NameToValue[] ntvTimeZone = { - new NameToValue("BEGIN", PropertyType.Begin), - new NameToValue("END", PropertyType.End), - new NameToValue("TZID", PropertyType.TimeZoneId), - new NameToValue("TZURL", PropertyType.TimeZoneUrl), - new NameToValue("LAST-MODIFIED", PropertyType.LastModified), + private static readonly NameToValue[] ntvTimeZone = + [ + new("BEGIN", PropertyType.Begin), + new("END", PropertyType.End), + new("TZID", PropertyType.TimeZoneId), + new("TZURL", PropertyType.TimeZoneUrl), + new("LAST-MODIFIED", PropertyType.LastModified), // The last entry should always be CustomProperty to catch all unrecognized properties. The actual // property name is not relevant. - new NameToValue("X-", PropertyType.Custom) - }; + new("X-", PropertyType.Custom) + ]; // Time zone observance rule items - private static NameToValue[] ntvORule = { - new NameToValue("BEGIN", PropertyType.Begin), - new NameToValue("END", PropertyType.End), - new NameToValue("DTSTART", PropertyType.StartDateTime), - new NameToValue("TZOFFSETFROM", PropertyType.TimeZoneOffsetFrom), - new NameToValue("TZOFFSETTO", PropertyType.TimeZoneOffsetTo), - new NameToValue("COMMENT", PropertyType.Comment), - new NameToValue("RRULE", PropertyType.RecurrenceRule), - new NameToValue("RDATE", PropertyType.RecurDate), - new NameToValue("TZNAME", PropertyType.TimeZoneName), + private static readonly NameToValue[] ntvORule = + [ + new("BEGIN", PropertyType.Begin), + new("END", PropertyType.End), + new("DTSTART", PropertyType.StartDateTime), + new("TZOFFSETFROM", PropertyType.TimeZoneOffsetFrom), + new("TZOFFSETTO", PropertyType.TimeZoneOffsetTo), + new("COMMENT", PropertyType.Comment), + new("RRULE", PropertyType.RecurrenceRule), + new("RDATE", PropertyType.RecurDate), + new("TZNAME", PropertyType.TimeZoneName), // The last entry should always be CustomProperty to catch all unrecognized properties. The actual // property name is not relevant. - new NameToValue("X-", PropertyType.Custom) - }; + new("X-", PropertyType.Custom) + ]; #endregion #region Properties @@ -332,7 +340,7 @@ protected enum VCalendarParserState /// The calendar from prior calls to the parsing methods is not cleared automatically. Call /// VCalendar.ClearProperties before calling a parsing method if you do not want to retain the /// calendar information from prior runs. - public VCalendar VCalendar => vCal; + public VCalendar? VCalendar => vCal; #endregion @@ -409,10 +417,10 @@ protected override void ResetState(bool fullReset) /// public static VCalendar ParseFromString(string calendarText) { - VCalendarParser vcp = new VCalendarParser(); + VCalendarParser vcp = new(); vcp.ParseString(calendarText); - return vcp.VCalendar; + return vcp.VCalendar!; } /// @@ -435,7 +443,7 @@ public static VCalendar ParseFromString(string calendarText) /// public static void ParseFromString(string calendarText, VCalendar calendar) { - VCalendarParser vcp = new VCalendarParser(calendar); + VCalendarParser vcp = new(calendar); vcp.ParseString(calendarText); } @@ -457,9 +465,9 @@ public static void ParseFromString(string calendarText, VCalendar calendar) /// "http://www.mydomain.com/Calendars/MySchedule.ics") /// /// - public static VCalendar ParseFromFile(string filename) + public static VCalendar? ParseFromFile(string filename) { - VCalendarParser vcp = new VCalendarParser(); + VCalendarParser vcp = new(); vcp.ParseFile(filename); return vcp.VCalendar; @@ -484,9 +492,9 @@ public static VCalendar ParseFromFile(string filename) /// sr.Close() /// /// - public static VCalendar ParseFromStream(TextReader stream) + public static VCalendar? ParseFromStream(TextReader stream) { - VCalendarParser vcp = new VCalendarParser(); + VCalendarParser vcp = new(); vcp.ParseReader(stream); return vcp.VCalendar; @@ -511,7 +519,6 @@ public static VCalendar ParseFromStream(TextReader stream) /// stream. Refer to the and inner exceptions for information on the cause of the problem. protected override void PropertyParser(string propertyName, StringCollection parameters, string propertyValue) { - SpecificationVersions version = SpecificationVersions.None; string temp; int idx; @@ -558,13 +565,17 @@ protected override void PropertyParser(string propertyName, StringCollection par // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntvCal.Length - 1; idx++) + { if(ntvCal[idx].IsMatch(propertyName)) break; + } // An opening BEGIN:VCALENDAR property must have been seen if(vCal == null && ntvCal[idx].EnumValue != PropertyType.Begin) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VCALENDAR", propertyName)); + } // Handle or create the property switch(ntvCal[idx].EnumValue) @@ -575,8 +586,10 @@ protected override void PropertyParser(string propertyName, StringCollection par // The last entry is always Custom so scan for length - 1 for(idx = 0; idx < ntvObjs.Length - 1; idx++) + { if(ntvObjs[idx].IsMatch(temp)) break; + } priorState.Push(currentState); currentState = ntvObjs[idx].EnumValue; @@ -587,28 +600,27 @@ protected override void PropertyParser(string propertyName, StringCollection par // NOTE: If serializing into an existing instance, this may not be null. If so, it // is ignored. It may also exist if two calendars appear in the same file. In that // case, they will be merged into one calendar. - if(vCal == null) - vCal = new VCalendar(); + vCal ??= new VCalendar(); break; case VCalendarParserState.VEvent: vEvent = new VEvent(); - vCal.Events.Add(vEvent); + vCal!.Events.Add(vEvent); break; case VCalendarParserState.VToDo: vToDo = new VToDo(); - vCal.ToDos.Add(vToDo); + vCal!.ToDos.Add(vToDo); break; case VCalendarParserState.VJournal: vJournal = new VJournal(); - vCal.Journals.Add(vJournal); + vCal!.Journals.Add(vJournal); break; case VCalendarParserState.VFreeBusy: vFreeBusy = new VFreeBusy(); - vCal.FreeBusys.Add(vFreeBusy); + vCal!.FreeBusys.Add(vFreeBusy); break; case VCalendarParserState.VTimeZone: @@ -630,58 +642,64 @@ protected override void PropertyParser(string propertyName, StringCollection par ntvCal[idx].Name, propertyValue)); // When done, we'll propagate the version number to all objects to make it consistent - vCal.PropagateVersion(); + vCal!.PropagateVersion(); break; case PropertyType.Version: // Version must be 1.0 or 2.0 temp = propertyValue.Trim(); + SpecificationVersions version; + if(temp == "1.0") version = SpecificationVersions.vCalendar10; else + { if(temp == "2.0") version = SpecificationVersions.iCalendar20; else + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedVersion", "vCalendar/iCalendar", temp)); + } + } - vCal.Version = version; + vCal!.Version = version; break; case PropertyType.ProductId: - vCal.ProductId.EncodedValue = propertyValue; + vCal!.ProductId.EncodedValue = propertyValue; break; case PropertyType.CalendarScale: - vCal.CalendarScale.DeserializeParameters(parameters); + vCal!.CalendarScale.DeserializeParameters(parameters); vCal.CalendarScale.EncodedValue = propertyValue; break; case PropertyType.Method: - vCal.Method.DeserializeParameters(parameters); + vCal!.Method.DeserializeParameters(parameters); vCal.Method.EncodedValue = propertyValue; break; case PropertyType.GeographicPosition: - vCal.VCalendarGeographicPosition.EncodedValue = propertyValue; + vCal!.VCalendarGeographicPosition.EncodedValue = propertyValue; break; case PropertyType.TimeZone: - vCal.VCalendarTimeZone.DeserializeParameters(parameters); + vCal!.VCalendarTimeZone.DeserializeParameters(parameters); vCal.VCalendarTimeZone.EncodedValue = propertyValue; break; case PropertyType.Daylight: - vCal.VCalendarDaylightRule.DeserializeParameters(parameters); + vCal!.VCalendarDaylightRule.DeserializeParameters(parameters); vCal.VCalendarDaylightRule.EncodedValue = propertyValue; break; default: // Anything else is a custom property - CustomProperty c = new CustomProperty(propertyName); + CustomProperty c = new(propertyName); c.DeserializeParameters(parameters); c.EncodedValue = propertyValue; - vCal.CustomProperties.Add(c); + vCal!.CustomProperties.Add(c); break; } } @@ -701,13 +719,17 @@ protected virtual void VEventParser(string propertyName, StringCollection parame // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntvEvent.Length - 1; idx++) + { if(ntvEvent[idx].IsMatch(propertyName)) break; + } // An opening BEGIN:VEVENT property must have been seen if(vEvent == null) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VEVENT", propertyName)); + } // Handle or create the property switch(ntvEvent[idx].EnumValue) @@ -733,8 +755,10 @@ protected virtual void VEventParser(string propertyName, StringCollection parame case PropertyType.End: // For this, the value must be VEVENT if(String.Compare(propertyValue.Trim(), "VEVENT", StringComparison.OrdinalIgnoreCase) != 0) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntvEvent[idx].Name, propertyValue)); + } // The event is added to the collection when created so we don't have to rely on an END tag // to add it. @@ -748,7 +772,7 @@ protected virtual void VEventParser(string propertyName, StringCollection parame case PropertyType.Categories: // If this is seen more than once, just add the new stuff to the existing property - CategoriesProperty cp = new CategoriesProperty(); + CategoriesProperty cp = new(); cp.DeserializeParameters(parameters); cp.EncodedValue = propertyValue; @@ -758,7 +782,7 @@ protected virtual void VEventParser(string propertyName, StringCollection parame case PropertyType.Resources: // If this is seen more than once, just add the new stuff to the existing property - ResourcesProperty rp = new ResourcesProperty(); + ResourcesProperty rp = new(); rp.DeserializeParameters(parameters); rp.EncodedValue = propertyValue; @@ -854,7 +878,7 @@ protected virtual void VEventParser(string propertyName, StringCollection parame break; case PropertyType.Contact: - ContactProperty c = new ContactProperty(); + ContactProperty c = new(); c.DeserializeParameters(parameters); c.EncodedValue = propertyValue; vEvent.Contacts.Add(c); @@ -866,21 +890,21 @@ protected virtual void VEventParser(string propertyName, StringCollection parame break; case PropertyType.Attendee: - AttendeeProperty ap = new AttendeeProperty(); + AttendeeProperty ap = new(); ap.DeserializeParameters(parameters); ap.EncodedValue = propertyValue; vEvent.Attendees.Add(ap); break; case PropertyType.RelatedTo: - RelatedToProperty rt = new RelatedToProperty(); + RelatedToProperty rt = new(); rt.DeserializeParameters(parameters); rt.EncodedValue = propertyValue; vEvent.RelatedTo.Add(rt); break; case PropertyType.Attachment: - AttachProperty att = new AttachProperty(); + AttachProperty att = new(); att.DeserializeParameters(parameters); att.EncodedValue = propertyValue; vEvent.Attachments.Add(att); @@ -897,7 +921,7 @@ protected virtual void VEventParser(string propertyName, StringCollection parame break; case PropertyType.RequestStatus: - RequestStatusProperty rs = new RequestStatusProperty(); + RequestStatusProperty rs = new(); rs.DeserializeParameters(parameters); rs.EncodedValue = propertyValue; vEvent.RequestStatuses.Add(rs); @@ -920,7 +944,7 @@ protected virtual void VEventParser(string propertyName, StringCollection parame break; case PropertyType.RecurrenceRule: - RRuleProperty rr = new RRuleProperty(); + RRuleProperty rr = new(); rr.DeserializeParameters(parameters); rr.EncodedValue = propertyValue; vEvent.RecurrenceRules.Add(rr); @@ -938,10 +962,9 @@ protected virtual void VEventParser(string propertyName, StringCollection parame foreach(string s in parts) { - sc = new StringCollection(); - sc.AddRange(parms); + sc = [.. parms]; - RDateProperty rd = new RDateProperty(); + RDateProperty rd = new(); rd.DeserializeParameters(sc); rd.EncodedValue = s; @@ -950,7 +973,7 @@ protected virtual void VEventParser(string propertyName, StringCollection parame break; case PropertyType.ExceptionRule: - ExRuleProperty er = new ExRuleProperty(); + ExRuleProperty er = new(); er.DeserializeParameters(parameters); er.EncodedValue = propertyValue; vEvent.ExceptionRules.Add(er); @@ -968,10 +991,9 @@ protected virtual void VEventParser(string propertyName, StringCollection parame foreach(string s in parts) { - sc = new StringCollection(); - sc.AddRange(parms); + sc = [.. parms]; - ExDateProperty ed = new ExDateProperty(); + ExDateProperty ed = new(); ed.DeserializeParameters(sc); ed.EncodedValue = s; @@ -985,7 +1007,7 @@ protected virtual void VEventParser(string propertyName, StringCollection parame break; default: // Anything else is a custom property - CustomProperty cust = new CustomProperty(propertyName); + CustomProperty cust = new(propertyName); cust.DeserializeParameters(parameters); cust.EncodedValue = propertyValue; vEvent.CustomProperties.Add(cust); @@ -1008,13 +1030,17 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntvToDo.Length - 1; idx++) + { if(ntvToDo[idx].IsMatch(propertyName)) break; + } // An opening BEGIN:VTODO property must have been seen if(vToDo == null) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VTODO", propertyName)); + } // Handle or create the property switch(ntvToDo[idx].EnumValue) @@ -1055,7 +1081,7 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet case PropertyType.Categories: // If this is seen more than once, just add the new stuff to the existing property - CategoriesProperty cp = new CategoriesProperty(); + CategoriesProperty cp = new(); cp.DeserializeParameters(parameters); cp.EncodedValue = propertyValue; @@ -1065,7 +1091,7 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet case PropertyType.Resources: // If this is seen more than once, just add the new stuff to the existing property - ResourcesProperty rp = new ResourcesProperty(); + ResourcesProperty rp = new(); rp.DeserializeParameters(parameters); rp.EncodedValue = propertyValue; @@ -1156,7 +1182,7 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet break; case PropertyType.Contact: - ContactProperty cont = new ContactProperty(); + ContactProperty cont = new(); cont.DeserializeParameters(parameters); cont.EncodedValue = propertyValue; vToDo.Contacts.Add(cont); @@ -1168,21 +1194,21 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet break; case PropertyType.Attendee: - AttendeeProperty ap = new AttendeeProperty(); + AttendeeProperty ap = new(); ap.DeserializeParameters(parameters); ap.EncodedValue = propertyValue; vToDo.Attendees.Add(ap); break; case PropertyType.RelatedTo: - RelatedToProperty rt = new RelatedToProperty(); + RelatedToProperty rt = new(); rt.DeserializeParameters(parameters); rt.EncodedValue = propertyValue; vToDo.RelatedTo.Add(rt); break; case PropertyType.Attachment: - AttachProperty att = new AttachProperty(); + AttachProperty att = new(); att.DeserializeParameters(parameters); att.EncodedValue = propertyValue; vToDo.Attachments.Add(att); @@ -1199,7 +1225,7 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet break; case PropertyType.RequestStatus: - RequestStatusProperty rs = new RequestStatusProperty(); + RequestStatusProperty rs = new(); rs.DeserializeParameters(parameters); rs.EncodedValue = propertyValue; vToDo.RequestStatuses.Add(rs); @@ -1227,7 +1253,7 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet break; case PropertyType.RecurrenceRule: - RRuleProperty rr = new RRuleProperty(); + RRuleProperty rr = new(); rr.DeserializeParameters(parameters); rr.EncodedValue = propertyValue; vToDo.RecurrenceRules.Add(rr); @@ -1245,10 +1271,9 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet foreach(string s in parts) { - sc = new StringCollection(); - sc.AddRange(parms); + sc = [.. parms]; - RDateProperty rd = new RDateProperty(); + RDateProperty rd = new(); rd.DeserializeParameters(sc); rd.EncodedValue = s; @@ -1257,7 +1282,7 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet break; case PropertyType.ExceptionRule: - ExRuleProperty er = new ExRuleProperty(); + ExRuleProperty er = new(); er.DeserializeParameters(parameters); er.EncodedValue = propertyValue; vToDo.ExceptionRules.Add(er); @@ -1275,10 +1300,9 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet foreach(string s in parts) { - sc = new StringCollection(); - sc.AddRange(parms); + sc = [.. parms]; - ExDateProperty ed = new ExDateProperty(); + ExDateProperty ed = new(); ed.DeserializeParameters(sc); ed.EncodedValue = s; @@ -1292,7 +1316,7 @@ protected virtual void VToDoParser(string propertyName, StringCollection paramet break; default: // Anything else is a custom property - CustomProperty cust = new CustomProperty(propertyName); + CustomProperty cust = new(propertyName); cust.DeserializeParameters(parameters); cust.EncodedValue = propertyValue; vToDo.CustomProperties.Add(cust); @@ -1315,13 +1339,17 @@ protected virtual void VJournalParser(string propertyName, StringCollection para // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntvJournal.Length - 1; idx++) + { if(ntvJournal[idx].IsMatch(propertyName)) break; + } // An opening BEGIN:VJOURNAL property must have been seen if(vJournal == null) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VJOURNAL", propertyName)); + } // Handle or create the property switch(ntvJournal[idx].EnumValue) @@ -1335,8 +1363,10 @@ protected virtual void VJournalParser(string propertyName, StringCollection para case PropertyType.End: // For this, the value must be VJOURNAL if(String.Compare(propertyValue.Trim(), "VJOURNAL", StringComparison.OrdinalIgnoreCase) != 0) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntvJournal[idx].Name, propertyValue)); + } // The journal is added to the collection when created so we don't have to rely on an END tag // to add it. @@ -1350,7 +1380,7 @@ protected virtual void VJournalParser(string propertyName, StringCollection para case PropertyType.Categories: // If this is seen more than once, just add the new stuff to the existing property - CategoriesProperty cp = new CategoriesProperty(); + CategoriesProperty cp = new(); cp.DeserializeParameters(parameters); cp.EncodedValue = propertyValue; @@ -1417,7 +1447,7 @@ protected virtual void VJournalParser(string propertyName, StringCollection para break; case PropertyType.Contact: - ContactProperty cont = new ContactProperty(); + ContactProperty cont = new(); cont.DeserializeParameters(parameters); cont.EncodedValue = propertyValue; vJournal.Contacts.Add(cont); @@ -1429,21 +1459,21 @@ protected virtual void VJournalParser(string propertyName, StringCollection para break; case PropertyType.Attendee: - AttendeeProperty ap = new AttendeeProperty(); + AttendeeProperty ap = new(); ap.DeserializeParameters(parameters); ap.EncodedValue = propertyValue; vJournal.Attendees.Add(ap); break; case PropertyType.RelatedTo: - RelatedToProperty rt = new RelatedToProperty(); + RelatedToProperty rt = new(); rt.DeserializeParameters(parameters); rt.EncodedValue = propertyValue; vJournal.RelatedTo.Add(rt); break; case PropertyType.Attachment: - AttachProperty att = new AttachProperty(); + AttachProperty att = new(); att.DeserializeParameters(parameters); att.EncodedValue = propertyValue; vJournal.Attachments.Add(att); @@ -1460,14 +1490,14 @@ protected virtual void VJournalParser(string propertyName, StringCollection para break; case PropertyType.RequestStatus: - RequestStatusProperty rs = new RequestStatusProperty(); + RequestStatusProperty rs = new(); rs.DeserializeParameters(parameters); rs.EncodedValue = propertyValue; vJournal.RequestStatuses.Add(rs); break; case PropertyType.RecurrenceRule: - RRuleProperty rr = new RRuleProperty(); + RRuleProperty rr = new(); rr.DeserializeParameters(parameters); rr.EncodedValue = propertyValue; vJournal.RecurrenceRules.Add(rr); @@ -1485,10 +1515,9 @@ protected virtual void VJournalParser(string propertyName, StringCollection para foreach(string s in parts) { - sc = new StringCollection(); - sc.AddRange(parms); + sc = [.. parms]; - RDateProperty rd = new RDateProperty(); + RDateProperty rd = new(); rd.DeserializeParameters(sc); rd.EncodedValue = s; @@ -1497,7 +1526,7 @@ protected virtual void VJournalParser(string propertyName, StringCollection para break; case PropertyType.ExceptionRule: - ExRuleProperty er = new ExRuleProperty(); + ExRuleProperty er = new(); er.DeserializeParameters(parameters); er.EncodedValue = propertyValue; vJournal.ExceptionRules.Add(er); @@ -1515,10 +1544,9 @@ protected virtual void VJournalParser(string propertyName, StringCollection para foreach(string s in parts) { - sc = new StringCollection(); - sc.AddRange(parms); + sc = [.. parms]; - ExDateProperty ed = new ExDateProperty(); + ExDateProperty ed = new(); ed.DeserializeParameters(sc); ed.EncodedValue = s; @@ -1532,7 +1560,7 @@ protected virtual void VJournalParser(string propertyName, StringCollection para break; default: // Anything else is a custom property - CustomProperty cust = new CustomProperty(propertyName); + CustomProperty cust = new(propertyName); cust.DeserializeParameters(parameters); cust.EncodedValue = propertyValue; vJournal.CustomProperties.Add(cust); @@ -1553,13 +1581,17 @@ protected virtual void VTimeZoneParser(string propertyName, StringCollection par // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntvTimeZone.Length - 1; idx++) + { if(ntvTimeZone[idx].IsMatch(propertyName)) break; + } // An opening BEGIN:VTIMEZONE property must have been seen if(vTimeZone == null) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VTIMEZONE", propertyName)); + } // Handle or create the property switch(ntvTimeZone[idx].EnumValue) @@ -1575,6 +1607,7 @@ protected virtual void VTimeZoneParser(string propertyName, StringCollection par currentState = VCalendarParserState.ObservanceRule; } else + { if(String.Compare(propertyValue.Trim(), "DAYLIGHT", StringComparison.OrdinalIgnoreCase) == 0) { obsRule = new ObservanceRule(ObservanceRuleType.Daylight); @@ -1587,13 +1620,16 @@ protected virtual void VTimeZoneParser(string propertyName, StringCollection par currentState = VCalendarParserState.Custom; CustomObjectParser(propertyName, parameters, propertyValue); } + } break; case PropertyType.End: // For this, the value must be VTIMEZONE if(String.Compare(propertyValue.Trim(), "VTIMEZONE", StringComparison.OrdinalIgnoreCase) != 0) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntvTimeZone[idx].Name, propertyValue)); + } // Unlike other objects, we do rely on the end tag to add the time zone object to the // collection as they are shared amongst all instances. @@ -1617,7 +1653,7 @@ protected virtual void VTimeZoneParser(string propertyName, StringCollection par break; default: // Anything else is a custom property - CustomProperty cust = new CustomProperty(propertyName); + CustomProperty cust = new(propertyName); cust.DeserializeParameters(parameters); cust.EncodedValue = propertyValue; vTimeZone.CustomProperties.Add(cust); @@ -1638,13 +1674,17 @@ protected virtual void VAlarmParser(string propertyName, StringCollection parame // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntvAlarm.Length - 1; idx++) + { if(ntvAlarm[idx].IsMatch(propertyName)) break; + } // An opening BEGIN:VALARM property must have been seen if(vAlarm == null) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VALARM", propertyName)); + } // Handle or create the property switch(ntvAlarm[idx].EnumValue) @@ -1658,8 +1698,10 @@ protected virtual void VAlarmParser(string propertyName, StringCollection parame case PropertyType.End: // For this, the value must be VALARM if(String.Compare(propertyValue.Trim(), "VALARM", StringComparison.OrdinalIgnoreCase) != 0) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntvAlarm[idx].Name, propertyValue)); + } // The alarm is added to the collection when created so we don't have to rely on an END tag // to add it. @@ -1698,21 +1740,21 @@ protected virtual void VAlarmParser(string propertyName, StringCollection parame break; case PropertyType.Attendee: - AttendeeProperty ap = new AttendeeProperty(); + AttendeeProperty ap = new(); ap.DeserializeParameters(parameters); ap.EncodedValue = propertyValue; vAlarm.Attendees.Add(ap); break; case PropertyType.Attachment: - AttachProperty att = new AttachProperty(); + AttachProperty att = new(); att.DeserializeParameters(parameters); att.EncodedValue = propertyValue; vAlarm.Attachments.Add(att); break; default: // Anything else is a custom property - CustomProperty cust = new CustomProperty(propertyName); + CustomProperty cust = new(propertyName); cust.DeserializeParameters(parameters); cust.EncodedValue = propertyValue; vAlarm.CustomProperties.Add(cust); @@ -1735,22 +1777,22 @@ protected virtual void ParseVCalendarAlarm(PropertyType propertyType, StringColl string[] parts = propertyValue.Split(';'); if(parts.Length != 0 && parts[0].Length > 0) - vAlarm.Trigger.EncodedValue = parts[0]; + vAlarm!.Trigger.EncodedValue = parts[0]; if(parts.Length > 1 && parts[1].Length > 0) - vAlarm.Duration.EncodedValue = parts[1]; + vAlarm!.Duration.EncodedValue = parts[1]; if(parts.Length > 2 && parts[2].Length > 0) - vAlarm.Repeat.EncodedValue = parts[2]; + vAlarm!.Repeat.EncodedValue = parts[2]; switch(propertyType) { case PropertyType.AudioAlarm: - vAlarm.Action.Action = AlarmAction.Audio; + vAlarm!.Action.Action = AlarmAction.Audio; if(parts.Length > 3 && parts[3].Length > 0) { - AttachProperty att = new AttachProperty(); + AttachProperty att = new(); att.DeserializeParameters(parameters); att.EncodedValue = parts[3]; vAlarm.Attachments.Add(att); @@ -1758,7 +1800,7 @@ protected virtual void ParseVCalendarAlarm(PropertyType propertyType, StringColl break; case PropertyType.DisplayAlarm: - vAlarm.Action.Action = AlarmAction.Display; + vAlarm!.Action.Action = AlarmAction.Display; if(parts.Length > 3 && parts[3].Length > 0) { @@ -1768,11 +1810,11 @@ protected virtual void ParseVCalendarAlarm(PropertyType propertyType, StringColl break; case PropertyType.EMailAlarm: - vAlarm.Action.Action = AlarmAction.EMail; + vAlarm!.Action.Action = AlarmAction.EMail; if(parts.Length > 3 && parts[3].Length > 0) { - AttendeeProperty ap = new AttendeeProperty(); + AttendeeProperty ap = new(); ap.DeserializeParameters(parameters); ap.EncodedValue = parts[3]; vAlarm.Attendees.Add(ap); @@ -1783,11 +1825,11 @@ protected virtual void ParseVCalendarAlarm(PropertyType propertyType, StringColl break; case PropertyType.ProcedureAlarm: - vAlarm.Action.Action = AlarmAction.Procedure; + vAlarm!.Action.Action = AlarmAction.Procedure; if(parts.Length > 3 && parts[3].Length > 0) { - AttachProperty att = new AttachProperty(); + AttachProperty att = new(); att.DeserializeParameters(parameters); att.EncodedValue = parts[3]; vAlarm.Attachments.Add(att); @@ -1811,13 +1853,17 @@ protected virtual void VFreeBusyParser(string propertyName, StringCollection par // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntvFreeBusy.Length - 1; idx++) + { if(ntvFreeBusy[idx].IsMatch(propertyName)) break; + } // An opening BEGIN:VFREEBUSY property must have been seen if(vFreeBusy == null) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VFREEBUSY", propertyName)); + } // Handle or create the property switch(ntvFreeBusy[idx].EnumValue) @@ -1831,8 +1877,10 @@ protected virtual void VFreeBusyParser(string propertyName, StringCollection par case PropertyType.End: // For this, the value must be VFREEBUSY if(String.Compare(propertyValue.Trim(), "VFREEBUSY", StringComparison.OrdinalIgnoreCase) != 0) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntvFreeBusy[idx].Name, propertyValue)); + } // The free/busy item is added to the collection when created so we don't have to rely on an // END tag to add it. @@ -1894,14 +1942,14 @@ protected virtual void VFreeBusyParser(string propertyName, StringCollection par break; case PropertyType.Attendee: - AttendeeProperty ap = new AttendeeProperty(); + AttendeeProperty ap = new(); ap.DeserializeParameters(parameters); ap.EncodedValue = propertyValue; vFreeBusy.Attendees.Add(ap); break; case PropertyType.RequestStatus: - RequestStatusProperty rs = new RequestStatusProperty(); + RequestStatusProperty rs = new(); rs.DeserializeParameters(parameters); rs.EncodedValue = propertyValue; vFreeBusy.RequestStatuses.Add(rs); @@ -1919,10 +1967,9 @@ protected virtual void VFreeBusyParser(string propertyName, StringCollection par foreach(string s in parts) { - sc = new StringCollection(); - sc.AddRange(parms); + sc = [.. parms]; - FreeBusyProperty fb = new FreeBusyProperty(); + FreeBusyProperty fb = new(); fb.DeserializeParameters(sc); fb.EncodedValue = s; @@ -1931,7 +1978,7 @@ protected virtual void VFreeBusyParser(string propertyName, StringCollection par break; default: // Anything else is a custom property - CustomProperty cust = new CustomProperty(propertyName); + CustomProperty cust = new(propertyName); cust.DeserializeParameters(parameters); cust.EncodedValue = propertyValue; vFreeBusy.CustomProperties.Add(cust); @@ -1954,13 +2001,17 @@ protected virtual void ObservanceRuleParser(string propertyName, StringCollectio // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntvORule.Length - 1; idx++) + { if(ntvORule[idx].IsMatch(propertyName)) break; + } // An opening BEGIN:STANDARD or BEGIN:DAYLIGHT property must have been seen. if(obsRule == null) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:STANDARD/BEGIN:DAYLIGHT", propertyName)); + } // Handle or create the property switch(ntvORule[idx].EnumValue) @@ -2018,7 +2069,7 @@ protected virtual void ObservanceRuleParser(string propertyName, StringCollectio break; case PropertyType.RecurrenceRule: - RRuleProperty rr = new RRuleProperty(); + RRuleProperty rr = new(); rr.DeserializeParameters(parameters); rr.EncodedValue = propertyValue; obsRule.RecurrenceRules.Add(rr); @@ -2036,10 +2087,9 @@ protected virtual void ObservanceRuleParser(string propertyName, StringCollectio foreach(string s in parts) { - sc = new StringCollection(); - sc.AddRange(parms); + sc = [.. parms]; - RDateProperty rd = new RDateProperty(); + RDateProperty rd = new(); rd.DeserializeParameters(sc); rd.EncodedValue = s; @@ -2048,14 +2098,14 @@ protected virtual void ObservanceRuleParser(string propertyName, StringCollectio break; case PropertyType.TimeZoneName: - TimeZoneNameProperty tzn = new TimeZoneNameProperty(); + TimeZoneNameProperty tzn = new(); tzn.DeserializeParameters(parameters); tzn.EncodedValue = propertyValue; obsRule.TimeZoneNames.Add(tzn); break; default: // Anything else is a custom property - CustomProperty cust = new CustomProperty(propertyName); + CustomProperty cust = new(propertyName); cust.DeserializeParameters(parameters); cust.EncodedValue = propertyValue; obsRule.CustomProperties.Add(cust); @@ -2075,38 +2125,38 @@ protected virtual void ObservanceRuleParser(string propertyName, StringCollectio /// processed. protected virtual void CustomObjectParser(string propertyName, StringCollection parameters, string propertyValue) { - CustomProperty cust = new CustomProperty(propertyName); + CustomProperty cust = new(propertyName); cust.DeserializeParameters(parameters); cust.EncodedValue = propertyValue; switch(priorState.Peek()) { case VCalendarParserState.VCalendar: - vCal.CustomProperties.Add(cust); + vCal!.CustomProperties.Add(cust); break; case VCalendarParserState.VEvent: - vEvent.CustomProperties.Add(cust); + vEvent!.CustomProperties.Add(cust); break; case VCalendarParserState.VToDo: - vToDo.CustomProperties.Add(cust); + vToDo!.CustomProperties.Add(cust); break; case VCalendarParserState.VJournal: - vJournal.CustomProperties.Add(cust); + vJournal!.CustomProperties.Add(cust); break; case VCalendarParserState.VAlarm: - vAlarm.CustomProperties.Add(cust); + vAlarm!.CustomProperties.Add(cust); break; case VCalendarParserState.VFreeBusy: - vFreeBusy.CustomProperties.Add(cust); + vFreeBusy!.CustomProperties.Add(cust); break; case VCalendarParserState.VTimeZone: - vTimeZone.CustomProperties.Add(cust); + vTimeZone!.CustomProperties.Add(cust); break; default: @@ -2116,8 +2166,11 @@ protected virtual void CustomObjectParser(string propertyName, StringCollection // Is it another nested object if(String.Compare(propertyName, "BEGIN", StringComparison.OrdinalIgnoreCase) == 0) beginValue.Push(propertyValue.Trim()); - else // Is it the end of the object? + else + { + // Is it the end of the object? if(String.Compare(propertyName, "END", StringComparison.OrdinalIgnoreCase) == 0) + { if(String.Compare(propertyValue.Trim(), beginValue.Peek(), StringComparison.OrdinalIgnoreCase) == 0) { beginValue.Pop(); @@ -2126,8 +2179,12 @@ protected virtual void CustomObjectParser(string propertyName, StringCollection currentState = priorState.Pop(); } else + { throw new PDIParserException(this.LineNumber, LR.GetString("ExCOPUnexpectedEnd", beginValue.Pop(), propertyValue)); + } + } + } } #endregion } diff --git a/Source/EWSPDIData/PDIParser/VCardParser.cs b/Source/EWSPDIData/PDIParser/VCardParser.cs index 78cd3de..22ec59b 100644 --- a/Source/EWSPDIData/PDIParser/VCardParser.cs +++ b/Source/EWSPDIData/PDIParser/VCardParser.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : VCardParser.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 07/24/2020 -// Note : Copyright 2004-2020, Eric Woodruff, All rights reserved +// Updated : 01/09/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a class used to parse vCard Personal Data Interchange (PDI) data streams. It supports // both the vCard 2.1 and vCard 3.0 specification file formats. @@ -37,57 +37,58 @@ public class VCardParser : PDIParser #region Private data members //===================================================================== - private VCard currentCard; // The current vCard being processed - private readonly VCardCollection vCards; // The collection of vCards + private VCard? currentCard; // The current vCard being processed + private readonly VCardCollection vCards; // The collection of vCards //===================================================================== // This private array is used to translate property names into property types - private static readonly NameToValue[] ntv = { - new NameToValue("BEGIN", PropertyType.Begin), - new NameToValue("END", PropertyType.End), - new NameToValue("VERSION", PropertyType.Version), - new NameToValue("PROFILE", PropertyType.Profile), - new NameToValue("KIND", PropertyType.Kind), - new NameToValue("NAME", PropertyType.MimeName), - new NameToValue("SOURCE", PropertyType.MimeSource), - new NameToValue("PRODID", PropertyType.ProductId), - new NameToValue("NICKNAME", PropertyType.Nickname), - new NameToValue("SORT-STRING", PropertyType.SortString), - new NameToValue("CLASS", PropertyType.Class), - new NameToValue("CATEGORIES", PropertyType.Categories), - new NameToValue("FN", PropertyType.FormattedName), - new NameToValue("N", PropertyType.Name), - new NameToValue("TITLE", PropertyType.Title), - new NameToValue("ROLE", PropertyType.Role), - new NameToValue("MAILER", PropertyType.Mailer), - new NameToValue("URL", PropertyType.Url), - new NameToValue("ORG", PropertyType.Organization), - new NameToValue("UID", PropertyType.UniqueId), - new NameToValue("BDAY", PropertyType.BirthDate), - new NameToValue("REV", PropertyType.Revision), - new NameToValue("TZ", PropertyType.TimeZone), - new NameToValue("GEO", PropertyType.GeographicPosition), - new NameToValue("KEY", PropertyType.PublicKey), - new NameToValue("PHOTO", PropertyType.Photo), - new NameToValue("LOGO", PropertyType.Logo), - new NameToValue("SOUND", PropertyType.Sound), - new NameToValue("NOTE", PropertyType.Note), - new NameToValue("ADR", PropertyType.Address), - new NameToValue("LABEL", PropertyType.Label), - new NameToValue("TEL", PropertyType.Telephone), - new NameToValue("EMAIL", PropertyType.EMail), - new NameToValue("AGENT", PropertyType.Agent), - new NameToValue("ANNIVERSARY", PropertyType.Anniversary), - new NameToValue("GENDER", PropertyType.Gender), - new NameToValue("CLIENTPIDMAP", PropertyType.ClientPidMap), - new NameToValue("MEMBER", PropertyType.Member), - new NameToValue("RELATED", PropertyType.Related), + private static readonly NameToValue[] ntv = + [ + new("BEGIN", PropertyType.Begin), + new("END", PropertyType.End), + new("VERSION", PropertyType.Version), + new("PROFILE", PropertyType.Profile), + new("KIND", PropertyType.Kind), + new("NAME", PropertyType.MimeName), + new("SOURCE", PropertyType.MimeSource), + new("PRODID", PropertyType.ProductId), + new("NICKNAME", PropertyType.Nickname), + new("SORT-STRING", PropertyType.SortString), + new("CLASS", PropertyType.Class), + new("CATEGORIES", PropertyType.Categories), + new("FN", PropertyType.FormattedName), + new("N", PropertyType.Name), + new("TITLE", PropertyType.Title), + new("ROLE", PropertyType.Role), + new("MAILER", PropertyType.Mailer), + new("URL", PropertyType.Url), + new("ORG", PropertyType.Organization), + new("UID", PropertyType.UniqueId), + new("BDAY", PropertyType.BirthDate), + new("REV", PropertyType.Revision), + new("TZ", PropertyType.TimeZone), + new("GEO", PropertyType.GeographicPosition), + new("KEY", PropertyType.PublicKey), + new("PHOTO", PropertyType.Photo), + new("LOGO", PropertyType.Logo), + new("SOUND", PropertyType.Sound), + new("NOTE", PropertyType.Note), + new("ADR", PropertyType.Address), + new("LABEL", PropertyType.Label), + new("TEL", PropertyType.Telephone), + new("EMAIL", PropertyType.EMail), + new("AGENT", PropertyType.Agent), + new("ANNIVERSARY", PropertyType.Anniversary), + new("GENDER", PropertyType.Gender), + new("CLIENTPIDMAP", PropertyType.ClientPidMap), + new("MEMBER", PropertyType.Member), + new("RELATED", PropertyType.Related), // The last entry should always be CustomProperty to catch all unrecognized properties. The actual // property name is not relevant. - new NameToValue("X-", PropertyType.Custom) - }; + new("X-", PropertyType.Custom) + ]; #endregion #region Properties @@ -112,7 +113,7 @@ public class VCardParser : PDIParser /// There are two overloads for the constructor public VCardParser() { - vCards = new VCardCollection(); + vCards = []; } /// @@ -149,9 +150,9 @@ protected VCardParser(VCard vCard) : this() /// Dim vCard As VCard = VCardParser.ParseFromString(oneVCard) /// /// - public static VCard ParseFromString(string vCardText) + public static VCard ParseFromString(string? vCardText) { - VCardParser vcp = new VCardParser(); + VCardParser vcp = new(); vcp.ParseString(vCardText); return vcp.VCards[0]; @@ -175,9 +176,9 @@ public static VCard ParseFromString(string vCardText) /// VCardParser.ParseFromString(oneVCard, vCard) /// /// - public static void ParseFromString(string vCardText, VCard vCard) + public static void ParseFromString(string? vCardText, VCard vCard) { - VCardParser vcp = new VCardParser(vCard); + VCardParser vcp = new(vCard); vcp.ParseString(vCardText); } @@ -195,9 +196,9 @@ public static void ParseFromString(string vCardText, VCard vCard) /// Dim vCards As VCardCollection = VCardParser.ParseSetFromString(vCards) /// /// - public static VCardCollection ParseSetFromString(string vCards) + public static VCardCollection ParseSetFromString(string? vCards) { - VCardParser vcp = new VCardParser(); + VCardParser vcp = new(); vcp.ParseString(vCards); return vcp.VCards; @@ -223,7 +224,7 @@ public static VCardCollection ParseSetFromString(string vCards) /// public static VCardCollection ParseFromFile(string filename) { - VCardParser vcp = new VCardParser(); + VCardParser vcp = new(); vcp.ParseFile(filename); return vcp.VCards; @@ -251,7 +252,7 @@ public static VCardCollection ParseFromFile(string filename) /// public static VCardCollection ParseFromStream(TextReader stream) { - VCardParser vcp = new VCardParser(); + VCardParser vcp = new(); vcp.ParseReader(stream); return vcp.VCards; @@ -276,7 +277,8 @@ public static VCardCollection ParseFromStream(TextReader stream) /// stream. Refer to the and inner exceptions for information on the cause of the problem. protected override void PropertyParser(string propertyName, StringCollection parameters, string propertyValue) { - string temp, group = null; + string temp; + string? group = null; int idx; // Parse out the group name if there is one @@ -290,13 +292,17 @@ protected override void PropertyParser(string propertyName, StringCollection par // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntv.Length - 1; idx++) + { if(ntv[idx].IsMatch(propertyName)) break; + } // An opening BEGIN:VCARD property must have been seen if(currentCard == null && ntv[idx].EnumValue != PropertyType.Begin) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VCARD", propertyName)); + } // Handle or create the property switch(ntv[idx].EnumValue) @@ -304,8 +310,10 @@ protected override void PropertyParser(string propertyName, StringCollection par case PropertyType.Begin: // The value must be VCARD if(String.Compare(propertyValue.Trim(), "VCARD", StringComparison.OrdinalIgnoreCase) != 0) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntv[idx].Name, propertyValue)); + } // NOTE: If serializing into an existing instance, this may not be null. If so, it is // ignored. @@ -325,9 +333,11 @@ protected override void PropertyParser(string propertyName, StringCollection par ntv[idx].Name, propertyValue)); // The group must match too - if(currentCard.Group != group) + if(currentCard!.Group != group) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnexpectedGroupTag", currentCard.Group, group)); + } // When done, we'll propagate the version number to all objects to make it consistent currentCard.PropagateVersion(); @@ -340,10 +350,12 @@ protected override void PropertyParser(string propertyName, StringCollection par case PropertyType.Profile: // The value must be VCARD if(String.Compare(propertyValue.Trim(), "VCARD", StringComparison.OrdinalIgnoreCase) != 0) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntv[idx].Name, propertyValue)); + } - currentCard.AddProfile = true; + currentCard!.AddProfile = true; break; case PropertyType.Version: @@ -355,214 +367,220 @@ protected override void PropertyParser(string propertyName, StringCollection par if(temp == "2.1") version = SpecificationVersions.vCard21; else + { if(temp == "3.0") version = SpecificationVersions.vCard30; else + { if(temp == "4.0") version = SpecificationVersions.vCard40; else + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedVersion", "vCard", temp)); + } + } + } - currentCard.Version = version; + currentCard!.Version = version; break; case PropertyType.MimeName: - currentCard.MimeName.EncodedValue = propertyValue; + currentCard!.MimeName.EncodedValue = propertyValue; break; case PropertyType.MimeSource: - currentCard.MimeSource.DeserializeParameters(parameters); + currentCard!.MimeSource.DeserializeParameters(parameters); currentCard.MimeSource.EncodedValue = propertyValue; break; case PropertyType.ProductId: - currentCard.ProductId.EncodedValue = propertyValue; + currentCard!.ProductId.EncodedValue = propertyValue; break; case PropertyType.Kind: - currentCard.Kind.DeserializeParameters(parameters); + currentCard!.Kind.DeserializeParameters(parameters); currentCard.Kind.EncodedValue = propertyValue; currentCard.Kind.Group = group; break; case PropertyType.Nickname: - currentCard.Nickname.DeserializeParameters(parameters); + currentCard!.Nickname.DeserializeParameters(parameters); currentCard.Nickname.EncodedValue = propertyValue; currentCard.Nickname.Group = group; break; case PropertyType.SortString: - currentCard.SortString.DeserializeParameters(parameters); + currentCard!.SortString.DeserializeParameters(parameters); currentCard.SortString.EncodedValue = propertyValue; currentCard.SortString.Group = group; break; case PropertyType.Class: - currentCard.Classification.EncodedValue = propertyValue; + currentCard!.Classification.EncodedValue = propertyValue; currentCard.Classification.Group = group; break; case PropertyType.Categories: - currentCard.Categories.DeserializeParameters(parameters); + currentCard!.Categories.DeserializeParameters(parameters); currentCard.Categories.EncodedValue = propertyValue; currentCard.Categories.Group = group; break; case PropertyType.FormattedName: - currentCard.FormattedName.DeserializeParameters(parameters); + currentCard!.FormattedName.DeserializeParameters(parameters); currentCard.FormattedName.EncodedValue = propertyValue; currentCard.FormattedName.Group = group; break; case PropertyType.Name: - currentCard.Name.DeserializeParameters(parameters); + currentCard!.Name.DeserializeParameters(parameters); currentCard.Name.EncodedValue = propertyValue; currentCard.Name.Group = group; break; case PropertyType.Gender: - currentCard.Gender.DeserializeParameters(parameters); + currentCard!.Gender.DeserializeParameters(parameters); currentCard.Gender.EncodedValue = propertyValue; currentCard.Gender.Group = group; break; case PropertyType.Title: - currentCard.Title.DeserializeParameters(parameters); + currentCard!.Title.DeserializeParameters(parameters); currentCard.Title.EncodedValue = propertyValue; currentCard.Title.Group = group; break; case PropertyType.Role: - currentCard.Role.DeserializeParameters(parameters); + currentCard!.Role.DeserializeParameters(parameters); currentCard.Role.EncodedValue = propertyValue; currentCard.Role.Group = group; break; case PropertyType.Mailer: - currentCard.Mailer.DeserializeParameters(parameters); + currentCard!.Mailer.DeserializeParameters(parameters); currentCard.Mailer.EncodedValue = propertyValue; currentCard.Mailer.Group = group; break; case PropertyType.Organization: - currentCard.Organization.DeserializeParameters(parameters); + currentCard!.Organization.DeserializeParameters(parameters); currentCard.Organization.EncodedValue = propertyValue; currentCard.Organization.Group = group; break; case PropertyType.UniqueId: - currentCard.UniqueId.EncodedValue = propertyValue; + currentCard!.UniqueId.EncodedValue = propertyValue; currentCard.UniqueId.Group = group; break; case PropertyType.BirthDate: - currentCard.BirthDate.DeserializeParameters(parameters); + currentCard!.BirthDate.DeserializeParameters(parameters); currentCard.BirthDate.EncodedValue = propertyValue; currentCard.BirthDate.Group = group; break; case PropertyType.Anniversary: - currentCard.Anniversary.DeserializeParameters(parameters); + currentCard!.Anniversary.DeserializeParameters(parameters); currentCard.Anniversary.EncodedValue = propertyValue; currentCard.Anniversary.Group = group; break; case PropertyType.Revision: - currentCard.LastRevision.DeserializeParameters(parameters); + currentCard!.LastRevision.DeserializeParameters(parameters); currentCard.LastRevision.EncodedValue = propertyValue; currentCard.LastRevision.Group = group; break; case PropertyType.TimeZone: - currentCard.TimeZone.DeserializeParameters(parameters); + currentCard!.TimeZone.DeserializeParameters(parameters); currentCard.TimeZone.EncodedValue = propertyValue; currentCard.TimeZone.Group = group; break; case PropertyType.GeographicPosition: - currentCard.GeographicPosition.EncodedValue = propertyValue; + currentCard!.GeographicPosition.EncodedValue = propertyValue; currentCard.GeographicPosition.Group = group; break; case PropertyType.PublicKey: - currentCard.PublicKey.DeserializeParameters(parameters); + currentCard!.PublicKey.DeserializeParameters(parameters); currentCard.PublicKey.EncodedValue = propertyValue; currentCard.PublicKey.Group = group; break; case PropertyType.Photo: - currentCard.Photo.DeserializeParameters(parameters); + currentCard!.Photo.DeserializeParameters(parameters); currentCard.Photo.EncodedValue = propertyValue; currentCard.Photo.Group = group; break; case PropertyType.Logo: - currentCard.Logo.DeserializeParameters(parameters); + currentCard!.Logo.DeserializeParameters(parameters); currentCard.Logo.EncodedValue = propertyValue; currentCard.Logo.Group = group; break; case PropertyType.Sound: - currentCard.Sound.DeserializeParameters(parameters); + currentCard!.Sound.DeserializeParameters(parameters); currentCard.Sound.EncodedValue = propertyValue; currentCard.Sound.Group = group; break; case PropertyType.Note: - NoteProperty n = new NoteProperty(); + NoteProperty n = new(); n.DeserializeParameters(parameters); n.EncodedValue = propertyValue; n.Group = group; - currentCard.Notes.Add(n); + currentCard!.Notes.Add(n); break; case PropertyType.Address: - AddressProperty a = new AddressProperty(); + AddressProperty a = new() { Version = currentCard!.Version }; a.DeserializeParameters(parameters); a.EncodedValue = propertyValue; a.Group = group; - currentCard.Addresses.Add(a); + currentCard!.Addresses.Add(a); break; case PropertyType.Label: - LabelProperty l = new LabelProperty(); + LabelProperty l = new() { Version = currentCard!.Version }; l.DeserializeParameters(parameters); l.EncodedValue = propertyValue; l.Group = group; - currentCard.Labels.Add(l); + currentCard!.Labels.Add(l); break; case PropertyType.Telephone: - TelephoneProperty t = new TelephoneProperty(); + TelephoneProperty t = new() { Version = currentCard!.Version }; t.DeserializeParameters(parameters); t.EncodedValue = propertyValue; t.Group = group; - currentCard.Telephones.Add(t); + currentCard!.Telephones.Add(t); break; case PropertyType.EMail: - EMailProperty e = new EMailProperty(); + EMailProperty e = new() { Version = currentCard!.Version }; e.DeserializeParameters(parameters); e.EncodedValue = propertyValue; e.Group = group; - currentCard.EMailAddresses.Add(e); + currentCard!.EMailAddresses.Add(e); break; case PropertyType.Url: - UrlProperty u = new UrlProperty(); + UrlProperty u = new(); u.DeserializeParameters(parameters); u.EncodedValue = propertyValue; u.Group = group; - currentCard.Urls.Add(u); + currentCard!.Urls.Add(u); break; case PropertyType.Agent: - AgentProperty ag = new AgentProperty(); + AgentProperty ag = new() { Version = currentCard!.Version }; ag.DeserializeParameters(parameters); ag.EncodedValue = propertyValue; ag.Group = group; - currentCard.Agents.Add(ag); + currentCard!.Agents.Add(ag); break; case PropertyType.ClientPidMap: @@ -570,7 +588,7 @@ protected override void PropertyParser(string propertyName, StringCollection par cpm.DeserializeParameters(parameters); cpm.EncodedValue = propertyValue; cpm.Group = group; - currentCard.ClientPidMaps.Add(cpm); + currentCard!.ClientPidMaps.Add(cpm); break; case PropertyType.Member: @@ -578,23 +596,23 @@ protected override void PropertyParser(string propertyName, StringCollection par member.DeserializeParameters(parameters); member.EncodedValue = propertyValue; member.Group = group; - currentCard.Members.Add(member); + currentCard!.Members.Add(member); break; case PropertyType.Related: - RelatedProperty r = new RelatedProperty(); + RelatedProperty r = new(); r.DeserializeParameters(parameters); r.EncodedValue = propertyValue; r.Group = group; - currentCard.Related.Add(r); + currentCard!.Related.Add(r); break; default: // Anything else is a custom property - CustomProperty c = new CustomProperty(propertyName); + CustomProperty c = new(propertyName); c.DeserializeParameters(parameters); c.EncodedValue = propertyValue; c.Group = group; - currentCard.CustomProperties.Add(c); + currentCard!.CustomProperties.Add(c); break; } } diff --git a/Source/EWSPDIData/PDIParser/VNoteParser.cs b/Source/EWSPDIData/PDIParser/VNoteParser.cs index 11134c9..85072fb 100644 --- a/Source/EWSPDIData/PDIParser/VNoteParser.cs +++ b/Source/EWSPDIData/PDIParser/VNoteParser.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : VNoteParser.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2007-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2007-2025, Eric Woodruff, All rights reserved // // This file contains a class used to parse vNote Personal Data Interchange (PDI) data streams. It supports // the IrMC 1.1 specification file format. @@ -37,28 +36,29 @@ public class VNoteParser : PDIParser #region Private data members //===================================================================== - private VNote currentNote; // The current vNote being processed - private VNoteCollection vNotes; // The collection of vNotes + private VNote? currentNote; // The current vNote being processed + private readonly VNoteCollection vNotes; // The collection of vNotes //===================================================================== // This private array is used to translate property names into property types - private static NameToValue[] ntv = { - new NameToValue("BEGIN", PropertyType.Begin), - new NameToValue("END", PropertyType.End), - new NameToValue("VERSION", PropertyType.Version), - new NameToValue("X-IRMC-LUID", PropertyType.UniqueId), - new NameToValue("SUMMARY", PropertyType.Summary), - new NameToValue("BODY", PropertyType.Body), - new NameToValue("DCREATED", PropertyType.DateCreated), - new NameToValue("LAST-MODIFIED", PropertyType.LastModified), - new NameToValue("CLASS", PropertyType.Class), - new NameToValue("CATEGORIES", PropertyType.Categories), + private static readonly NameToValue[] ntv = + [ + new("BEGIN", PropertyType.Begin), + new("END", PropertyType.End), + new("VERSION", PropertyType.Version), + new("X-IRMC-LUID", PropertyType.UniqueId), + new("SUMMARY", PropertyType.Summary), + new("BODY", PropertyType.Body), + new("DCREATED", PropertyType.DateCreated), + new("LAST-MODIFIED", PropertyType.LastModified), + new("CLASS", PropertyType.Class), + new("CATEGORIES", PropertyType.Categories), // The last entry should always be CustomProperty to catch all unrecognized properties. The actual // property name is not relevant. - new NameToValue("X-", PropertyType.Custom) - }; + new("X-", PropertyType.Custom) + ]; #endregion #region Properties @@ -83,7 +83,7 @@ public class VNoteParser : PDIParser /// There are two overloads for the constructor public VNoteParser() { - vNotes = new VNoteCollection(); + vNotes = []; } /// @@ -122,7 +122,7 @@ protected VNoteParser(VNote vNote) : this() /// public static VNote ParseFromString(string vNoteText) { - VNoteParser vcp = new VNoteParser(); + VNoteParser vcp = new(); vcp.ParseString(vNoteText); return vcp.VNotes[0]; @@ -148,7 +148,7 @@ public static VNote ParseFromString(string vNoteText) /// public static void ParseFromString(string vNoteText, VNote vNote) { - VNoteParser vcp = new VNoteParser(vNote); + VNoteParser vcp = new(vNote); vcp.ParseString(vNoteText); } @@ -168,7 +168,7 @@ public static void ParseFromString(string vNoteText, VNote vNote) /// public static VNoteCollection ParseSetFromString(string vNotes) { - VNoteParser vcp = new VNoteParser(); + VNoteParser vcp = new(); vcp.ParseString(vNotes); return vcp.VNotes; @@ -194,7 +194,7 @@ public static VNoteCollection ParseSetFromString(string vNotes) /// public static VNoteCollection ParseFromFile(string filename) { - VNoteParser vcp = new VNoteParser(); + VNoteParser vcp = new(); vcp.ParseFile(filename); return vcp.VNotes; @@ -222,7 +222,7 @@ public static VNoteCollection ParseFromFile(string filename) /// public static VNoteCollection ParseFromStream(TextReader stream) { - VNoteParser vcp = new VNoteParser(); + VNoteParser vcp = new(); vcp.ParseReader(stream); return vcp.VNotes; @@ -252,13 +252,17 @@ protected override void PropertyParser(string propertyName, StringCollection par // The last entry is always CustomProperty so scan for length minus one for(idx = 0; idx < ntv.Length - 1; idx++) + { if(ntv[idx].IsMatch(propertyName)) break; + } // An opening BEGIN:VNOTE property must have been seen if(currentNote == null && ntv[idx].EnumValue != PropertyType.Begin) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VNOTE", propertyName)); + } // Handle or create the property switch(ntv[idx].EnumValue) @@ -266,8 +270,10 @@ protected override void PropertyParser(string propertyName, StringCollection par case PropertyType.Begin: // The value must be VNOTE if(String.Compare(propertyValue.Trim(), "VNOTE", StringComparison.OrdinalIgnoreCase) != 0) + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntv[idx].Name, propertyValue)); + } // NOTE: If serializing into an existing instance, this may not be null. If so, it is // ignored. @@ -285,7 +291,7 @@ protected override void PropertyParser(string propertyName, StringCollection par ntv[idx].Name, propertyValue)); // When done, we'll propagate the version number to all objects to make it consistent - currentNote.PropagateVersion(); + currentNote!.PropagateVersion(); // The vNote is added to the collection when created so we don't have to rely on an END:VNOTE // to add it. @@ -297,50 +303,52 @@ protected override void PropertyParser(string propertyName, StringCollection par temp = propertyValue.Trim(); if(temp != "1.1") + { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedVersion", "vNote", temp)); + } - currentNote.Version = SpecificationVersions.IrMC11; + currentNote!.Version = SpecificationVersions.IrMC11; break; case PropertyType.UniqueId: - currentNote.UniqueId.EncodedValue = propertyValue; + currentNote!.UniqueId.EncodedValue = propertyValue; break; case PropertyType.Summary: - currentNote.Summary.DeserializeParameters(parameters); + currentNote!.Summary.DeserializeParameters(parameters); currentNote.Summary.EncodedValue = propertyValue; break; case PropertyType.Body: - currentNote.Body.DeserializeParameters(parameters); + currentNote!.Body.DeserializeParameters(parameters); currentNote.Body.EncodedValue = propertyValue; break; case PropertyType.Class: - currentNote.Classification.EncodedValue = propertyValue; + currentNote!.Classification.EncodedValue = propertyValue; break; case PropertyType.Categories: - currentNote.Categories.DeserializeParameters(parameters); + currentNote!.Categories.DeserializeParameters(parameters); currentNote.Categories.EncodedValue = propertyValue; break; case PropertyType.DateCreated: - currentNote.DateCreated.DeserializeParameters(parameters); + currentNote!.DateCreated.DeserializeParameters(parameters); currentNote.DateCreated.EncodedValue = propertyValue; break; case PropertyType.LastModified: - currentNote.LastModified.DeserializeParameters(parameters); + currentNote!.LastModified.DeserializeParameters(parameters); currentNote.LastModified.EncodedValue = propertyValue; break; default: // Anything else is a custom property - CustomProperty c = new CustomProperty(propertyName); + CustomProperty c = new(propertyName); c.DeserializeParameters(parameters); c.EncodedValue = propertyValue; - currentNote.CustomProperties.Add(c); + currentNote!.CustomProperties.Add(c); break; } } diff --git a/Source/EWSPDIData/PDIProperties/ActionProperty.cs b/Source/EWSPDIData/PDIProperties/ActionProperty.cs index 135bc25..4cba97a 100644 --- a/Source/EWSPDIData/PDIProperties/ActionProperty.cs +++ b/Source/EWSPDIData/PDIProperties/ActionProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ActionProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Action property used by the Personal Data Interchange (PDI) vCalendar and iCalendar // VAlarm class. @@ -35,7 +34,7 @@ public class ActionProperty : BaseProperty //===================================================================== private AlarmAction alarmAction; - private string otherAction; + private string? otherAction; #endregion @@ -74,8 +73,10 @@ public AlarmAction Action if(alarmAction != AlarmAction.Other) otherAction = null; else + { if(String.IsNullOrWhiteSpace(otherAction)) - otherAction = "X-UNKNOWN"; + otherAction = "X-UNKNOWN"; + } } } @@ -85,7 +86,7 @@ public AlarmAction Action /// /// Setting this parameter automatically sets the property to /// Other. - public string OtherAction + public string? OtherAction { get => otherAction; set @@ -102,7 +103,7 @@ public string OtherAction /// /// This property is overridden to handle converting the text value to an value /// - public override string Value + public override string? Value { get { @@ -151,7 +152,7 @@ public override string Value /// /// This property is overridden to handle converting the text value to an value /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -179,7 +180,7 @@ public ActionProperty() /// A clone of the object public override object Clone() { - ActionProperty o = new ActionProperty(); + ActionProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/AddressProperty.cs b/Source/EWSPDIData/PDIProperties/AddressProperty.cs index 1cdacbd..2af4433 100644 --- a/Source/EWSPDIData/PDIProperties/AddressProperty.cs +++ b/Source/EWSPDIData/PDIProperties/AddressProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : AddressProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/18/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Address property. It is used with the Personal Data Interchange (PDI) vCard class // @@ -41,25 +41,26 @@ public class AddressProperty : BaseProperty #region Private data members //===================================================================== - private static readonly Regex reSplitSemiColon = new Regex(@"(?:^[;])|(?<=(?:[^\\]))[;]"); - private static readonly Regex reSplitComma = new Regex(@"(?:^[,])|(?<=(?:[^\\]))[,]"); + private static readonly Regex reSplitSemiColon = new(@"(?:^[;])|(?<=(?:[^\\]))[;]"); + private static readonly Regex reSplitComma = new(@"(?:^[,])|(?<=(?:[^\\]))[,]"); //===================================================================== // This private array is used to translate parameter names and values to address types. - private static readonly NameToValue[] ntv = { - new NameToValue("GEO", AddressTypes.None, false), - new NameToValue("LABEL", AddressTypes.None, false), - new NameToValue("TZ", AddressTypes.None, false), - new NameToValue("TYPE", AddressTypes.None, false), - new NameToValue("DOM", AddressTypes.Domestic, true), - new NameToValue("INTL", AddressTypes.International, true), - new NameToValue("POSTAL", AddressTypes.Postal, true), - new NameToValue("PARCEL", AddressTypes.Parcel, true), - new NameToValue("HOME", AddressTypes.Home, true), - new NameToValue("WORK", AddressTypes.Work, true), - new NameToValue("PREF", AddressTypes.Preferred, true) - }; + private static readonly NameToValue[] ntv = + [ + new("GEO", AddressTypes.None, false), + new("LABEL", AddressTypes.None, false), + new("TZ", AddressTypes.None, false), + new("TYPE", AddressTypes.None, false), + new("DOM", AddressTypes.Domestic, true), + new("INTL", AddressTypes.International, true), + new("POSTAL", AddressTypes.Postal, true), + new("PARCEL", AddressTypes.Parcel, true), + new("HOME", AddressTypes.Home, true), + new("WORK", AddressTypes.Work, true), + new("PREF", AddressTypes.Preferred, true) + ]; private short preferredOrder; @@ -111,65 +112,65 @@ public short PreferredOrder /// /// This property is used to get or set the geocoded location /// - public string Geo { get; set; } + public string? Geo { get; set; } /// /// This property is used to get or set the label (the address in a format suitable for printing as an /// address label. /// - public string Label { get; set; } + public string? Label { get; set; } /// /// This property is used to get or set the time zone associated with the address /// - public string TimeZone { get; set; } + public string? TimeZone { get; set; } /// /// This property is used to set or get the PO Box /// - public string POBox { get; set; } + public string ?POBox { get; set; } /// /// This property is used to set or get the extended address /// - public string ExtendedAddress { get; set; } + public string? ExtendedAddress { get; set; } /// /// This property is used to set or get the street address /// - public string StreetAddress { get; set; } + public string? StreetAddress { get; set; } /// /// This property is used to set or get the locality (i.e. city) /// - public string Locality { get; set; } + public string? Locality { get; set; } /// /// This property is used to set or get the region (i.e. state or province) /// - public string Region { get; set; } + public string? Region { get; set; } /// /// This property is used to set or get the postal (zip) code /// - public string PostalCode { get; set; } + public string? PostalCode { get; set; } /// /// This property is used to set or get the country /// - public string Country { get; set; } + public string? Country { get; set; } /// /// This property is overridden to handle parsing the address components and concatenating them when /// requested. /// /// The component parts are escaped as needed - public override string Value + public override string? Value { get { SpecificationVersions v = this.Version; - string[] parts = new string[8]; + string?[] parts = new string[8]; int count = 0; // Only include as much as necessary @@ -290,15 +291,15 @@ public override string Value /// requested. /// /// The component parts are escaped as needed - public override string EncodedValue + public override string? EncodedValue { get { - string addrValue = this.Value; + string? addrValue = this.Value; // Encode using the character set? If so, unescape the backslashes as they get double-encoded. if(addrValue != null && this.Version == SpecificationVersions.vCard21) - addrValue = base.Encode(addrValue).Replace(@"\\", @"\"); + addrValue = base.Encode(addrValue)?.Replace(@"\\", @"\"); return addrValue; } @@ -329,7 +330,7 @@ public AddressProperty() /// A clone of the object public override object Clone() { - AddressProperty o = new AddressProperty(); + AddressProperty o = new(); o.Clone(this); return o; } @@ -388,9 +389,10 @@ public override void SerializeParameters(StringBuilder sb) // Serialize the address types if necessary if(parameterValue != AddressTypes.None && parameterValue != defaultValue) { - StringBuilder sbTypes = new StringBuilder(50); + StringBuilder sbTypes = new(50); for(int idx = 1; idx < ntv.Length; idx++) + { if((parameterValue & ntv[idx].EnumValue) != 0) { if(sbTypes.Length > 0) @@ -398,6 +400,7 @@ public override void SerializeParameters(StringBuilder sb) sbTypes.Append(ntv[idx].Name); } + } // The format is different for the 3.0 and later specs if(this.Version == SpecificationVersions.vCard21) @@ -476,8 +479,10 @@ public override void DeserializeParameters(StringCollection parameters) foreach(string s in types) { for(subIdx = 1; subIdx < ntv.Length; subIdx++) + { if(ntv[subIdx].IsMatch(s)) break; + } // Unrecognized ones are ignored if(subIdx < ntv.Length) diff --git a/Source/EWSPDIData/PDIProperties/AddressPropertyCollection.cs b/Source/EWSPDIData/PDIProperties/AddressPropertyCollection.cs index 8405501..1217542 100644 --- a/Source/EWSPDIData/PDIProperties/AddressPropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/AddressPropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : AddressPropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for AddressProperty objects. It is used with the Personal Data // Interchange (PDI) vCard class. @@ -99,10 +98,12 @@ public void SetPreferred(int idx) throw new ArgumentOutOfRangeException(nameof(idx), idx, LR.GetString("ExAddrInvalidIndex")); for(int addrIdx = 0; addrIdx < base.Count; addrIdx++) + { if(addrIdx == idx) this[addrIdx].AddressTypes |= AddressTypes.Preferred; else this[addrIdx].AddressTypes &= ~AddressTypes.Preferred; + } base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } @@ -116,15 +117,19 @@ public void SetPreferred(int idx) /// the one with the Preferred flag set. If a preferred address with one of the given types /// cannot be found, it will return the first address matching one of the given types without the /// Preferred flag set. If no address can be found, it returns null. - public AddressProperty FindFirstByType(AddressTypes addrType) + public AddressProperty? FindFirstByType(AddressTypes addrType) { AddressTypes addrNoPref = addrType & ~AddressTypes.Preferred; bool usePreferred = (addrNoPref != addrType); foreach(AddressProperty addr in this) + { if((addr.AddressTypes & addrNoPref) != 0 && (!usePreferred || (addr.AddressTypes & AddressTypes.Preferred) != 0)) + { return addr; + } + } // Try again without the preferred flag? if(usePreferred) diff --git a/Source/EWSPDIData/PDIProperties/AgentProperty.cs b/Source/EWSPDIData/PDIProperties/AgentProperty.cs index b1d29a5..c16cf23 100644 --- a/Source/EWSPDIData/PDIProperties/AgentProperty.cs +++ b/Source/EWSPDIData/PDIProperties/AgentProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : AgentProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Agent property. It is used with the Personal Data Interchange (PDI) classes such as // vCalendar, iCalendar, and vCard. @@ -37,7 +36,7 @@ public class AgentProperty : BaseProperty #region Private data members //===================================================================== - private VCard agent; + private VCard? agent; #endregion @@ -71,7 +70,7 @@ public class AgentProperty : BaseProperty /// vCard. This property returns it as a parsed vCard object. It can also be used to set or modify the /// vCard object. Null is returned if no agent is defined or the value is not inline. If set to a vCard /// object, the location is forced to be inline. - public VCard VCard + public VCard? VCard { get => agent; set @@ -87,7 +86,7 @@ public VCard VCard /// If inline, the value is stored as a vCard object. If not inline, it is stored as a text /// string. /// This is thrown if the vCard data is not valid - public override string Value + public override string? Value { get { @@ -115,7 +114,7 @@ public override string Value /// If inline, the value is stored as a vCard object. If not inline, it is stored as a text /// string. /// This is thrown if the vCard data is not valid - public override string EncodedValue + public override string? EncodedValue { get { @@ -158,7 +157,7 @@ public AgentProperty() /// A clone of the object public override object Clone() { - AgentProperty o = new AgentProperty(); + AgentProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/AgentPropertyCollection.cs b/Source/EWSPDIData/PDIProperties/AgentPropertyCollection.cs index d538891..87229d9 100644 --- a/Source/EWSPDIData/PDIProperties/AgentPropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/AgentPropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : AgentPropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for AgentProperty objects. It is used with the Personal Data // Interchange (PDI) classes such as vCalendar, iCalendar, and vCard. @@ -64,9 +63,9 @@ public AgentPropertyCollection(IList agents) : base(agents) /// Returns the new property that was created and added to the collection public AgentProperty Add(VCard vCard) { - AgentProperty a = new AgentProperty { VCard = vCard }; + AgentProperty a = new() { VCard = vCard }; - base.Add(a); + this.Add(a); return a; } @@ -80,7 +79,7 @@ public void PropagateVersion(SpecificationVersions version) foreach(PDIObject o in this) o.Version = version; - base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); + this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } #endregion } diff --git a/Source/EWSPDIData/PDIProperties/AnniversaryProperty.cs b/Source/EWSPDIData/PDIProperties/AnniversaryProperty.cs index 4402fb4..3c7e81e 100644 --- a/Source/EWSPDIData/PDIProperties/AnniversaryProperty.cs +++ b/Source/EWSPDIData/PDIProperties/AnniversaryProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : AnniversaryProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 05/17/2019 -// Note : Copyright 2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/23/2025 +// Note : Copyright 2019-2025, Eric Woodruff, All rights reserved // // This file contains the Anniversary property class used by the Personal Data Interchange (PDI) vCard classes // @@ -70,7 +69,7 @@ public AnniversaryProperty() /// A clone of the object public override object Clone() { - AnniversaryProperty o = new AnniversaryProperty(); + AnniversaryProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/AttachProperty.cs b/Source/EWSPDIData/PDIProperties/AttachProperty.cs index 466cd81..457701e 100644 --- a/Source/EWSPDIData/PDIProperties/AttachProperty.cs +++ b/Source/EWSPDIData/PDIProperties/AttachProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : BinaryProperties.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Attach property that support binary encoded attachments. It is used with the Personal // Data Interchange (PDI) vCalendar and iCalendar classes. @@ -59,7 +58,7 @@ public class AttachProperty : BaseProperty /// /// The value is a string defining the type of attachment that the property value represents such /// as image/jpeg, application/binary, audio/basic, etc. - public string FormatType { get; set; } + public string? FormatType { get; set; } #endregion @@ -83,7 +82,7 @@ public AttachProperty() /// A clone of the object public override object Clone() { - AttachProperty o = new AttachProperty(); + AttachProperty o = new(); o.Clone(this); return o; } @@ -126,6 +125,7 @@ public override void DeserializeParameters(StringCollection parameters) return; for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) + { if(String.Compare(parameters[paramIdx], "FMTTYPE=", StringComparison.OrdinalIgnoreCase) == 0) { // Remove the parameter name @@ -140,6 +140,7 @@ public override void DeserializeParameters(StringCollection parameters) } break; } + } // Let the base class handle all other parameters base.DeserializeParameters(parameters); diff --git a/Source/EWSPDIData/PDIProperties/AttendeeProperty.cs b/Source/EWSPDIData/PDIProperties/AttendeeProperty.cs index 372eaad..777e471 100644 --- a/Source/EWSPDIData/PDIProperties/AttendeeProperty.cs +++ b/Source/EWSPDIData/PDIProperties/AttendeeProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : AttendeeProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Attendee property used by the vCalendar and iCalendar classes // @@ -43,40 +42,41 @@ public class AttendeeProperty : OrganizerProperty #region Private data members //===================================================================== - private StringCollection delFrom, delTo, member; + private StringCollection delFrom = null!, delTo = null!, member = null!; // This is used to map parameter name and value strings to a ParameterType enumeration - private static NameToValue[] ntv = { - new NameToValue(ParameterNames.Role, ParameterType.Role), - new NameToValue(ParameterNames.Rsvp, ParameterType.Rsvp), - new NameToValue(ParameterNames.Expect, ParameterType.Expect), - new NameToValue(ParameterNames.CalendarUserType, ParameterType.CalendarUserType), - new NameToValue(ParameterNames.DelegatedFrom, ParameterType.DelegatedFrom), - new NameToValue(ParameterNames.DelegatedTo, ParameterType.DelegatedTo), - new NameToValue(ParameterNames.Member, ParameterType.Member), - new NameToValue(ParameterNames.Status, ParameterType.Status), - new NameToValue(ParameterNames.PartStatus, ParameterType.Status), - new NameToValue("ATTENDEE", ParameterType.Role, true), - new NameToValue("ORGANIZER", ParameterType.Role, true), - new NameToValue("OWNER", ParameterType.Role, true), - new NameToValue("DELEGATE", ParameterType.Role, true), - new NameToValue("ACCEPTED", ParameterType.Status, true), - new NameToValue("NEEDS ACTION", ParameterType.Status, true), - new NameToValue("NEEDS-ACTION", ParameterType.Status, true), - new NameToValue("NEEDSACTION", ParameterType.Status, true), - new NameToValue("SENT", ParameterType.Status, true), - new NameToValue("TENTATIVE", ParameterType.Status, true), - new NameToValue("CONFIRMED", ParameterType.Status, true), - new NameToValue("DECLINED", ParameterType.Status, true), - new NameToValue("COMPLETED", ParameterType.Status, true), - new NameToValue("DELEGATED", ParameterType.Status, true), - new NameToValue("YES", ParameterType.Rsvp, true), - new NameToValue("NO", ParameterType.Rsvp, true), - new NameToValue("FYI", ParameterType.Expect, true), - new NameToValue("REQUIRE", ParameterType.Expect, true), - new NameToValue("REQUEST", ParameterType.Expect, true), - new NameToValue("IMMEDIATE", ParameterType.Expect, true) - }; + private static readonly NameToValue[] ntv = + [ + new(ParameterNames.Role, ParameterType.Role), + new(ParameterNames.Rsvp, ParameterType.Rsvp), + new(ParameterNames.Expect, ParameterType.Expect), + new(ParameterNames.CalendarUserType, ParameterType.CalendarUserType), + new(ParameterNames.DelegatedFrom, ParameterType.DelegatedFrom), + new(ParameterNames.DelegatedTo, ParameterType.DelegatedTo), + new(ParameterNames.Member, ParameterType.Member), + new(ParameterNames.Status, ParameterType.Status), + new(ParameterNames.PartStatus, ParameterType.Status), + new("ATTENDEE", ParameterType.Role, true), + new("ORGANIZER", ParameterType.Role, true), + new("OWNER", ParameterType.Role, true), + new("DELEGATE", ParameterType.Role, true), + new("ACCEPTED", ParameterType.Status, true), + new("NEEDS ACTION", ParameterType.Status, true), + new("NEEDS-ACTION", ParameterType.Status, true), + new("NEEDSACTION", ParameterType.Status, true), + new("SENT", ParameterType.Status, true), + new("TENTATIVE", ParameterType.Status, true), + new("CONFIRMED", ParameterType.Status, true), + new("DECLINED", ParameterType.Status, true), + new("COMPLETED", ParameterType.Status, true), + new("DELEGATED", ParameterType.Status, true), + new("YES", ParameterType.Rsvp, true), + new("NO", ParameterType.Rsvp, true), + new("FYI", ParameterType.Expect, true), + new("REQUIRE", ParameterType.Expect, true), + new("REQUEST", ParameterType.Expect, true), + new("IMMEDIATE", ParameterType.Expect, true) + ]; #endregion #region Properties @@ -100,14 +100,14 @@ public class AttendeeProperty : OrganizerProperty /// /// This parameter is only applicable to iCalendar 2.0 objects. It is used to define the type of /// calendar user specified by the property such as INDIVIDUAL, GROUP, RESOURCE, etc. - public string CalendarUserType { get; set; } + public string? CalendarUserType { get; set; } /// /// This property is used to set or get the calendar user expectation (EXPECT) parameter for the calendar /// user specified by the property value. /// /// This parameter is only applicable to vCalendar 1.0 objects - public string Expectation { get; set; } + public string? Expectation { get; set; } /// /// This property is used to set or get the "delegated from" (DELEGATED-FROM) parameters for the calendar @@ -119,8 +119,7 @@ public StringCollection DelegatedFrom { get { - if(delFrom == null) - delFrom = new StringCollection(); + delFrom ??= []; return delFrom; } @@ -136,8 +135,7 @@ public StringCollection DelegatedTo { get { - if(delTo == null) - delTo = new StringCollection(); + delTo ??= []; return delTo; } @@ -153,8 +151,7 @@ public StringCollection Membership { get { - if(member == null) - member = new StringCollection(); + member ??= []; return member; } @@ -165,14 +162,14 @@ public StringCollection Membership /// property value. /// /// This parameter is applicable to vCalendar and iCalendar objects - public string Role { get; set; } + public string? Role { get; set; } /// /// This property is used to set or get the participation status parameter (STATUS for vCalendar, /// PART-STATUS for iCalendar) for the calendar user specified by the property value. /// /// This parameter is applicable to vCalendar and iCalendar objects - public string ParticipationStatus { get; set; } + public string? ParticipationStatus { get; set; } /// /// This property is used to set or get the RSVP (RSVP) parameter for the calendar user specified by the @@ -203,7 +200,7 @@ public AttendeeProperty() /// A clone of the object public override object Clone() { - AttendeeProperty o = new AttendeeProperty(); + AttendeeProperty o = new(); o.Clone(this); return o; } @@ -377,8 +374,10 @@ public override void DeserializeParameters(StringCollection parameters) for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) { for(idx = 0; idx < ntv.Length; idx++) + { if(ntv[idx].IsMatch(parameters[paramIdx])) break; + } if(idx == ntv.Length) { diff --git a/Source/EWSPDIData/PDIProperties/AttendeePropertyCollection.cs b/Source/EWSPDIData/PDIProperties/AttendeePropertyCollection.cs index 4e78b24..86f27a4 100644 --- a/Source/EWSPDIData/PDIProperties/AttendeePropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/AttendeePropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : AttendeeProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for AttendeeProperty objects // @@ -63,7 +62,7 @@ public AttendeePropertyCollection(IList attendees) : base(atte /// There are two overloads for this method public AttendeeProperty Add(string attendee) { - AttendeeProperty a = new AttendeeProperty { Value = attendee }; + AttendeeProperty a = new() { Value = attendee }; base.Add(a); @@ -79,7 +78,7 @@ public AttendeeProperty Add(string attendee) /// Returns the new property that was created and added to the collection public AttendeeProperty Add(string attendee, string commonName) { - AttendeeProperty a = new AttendeeProperty { Value = attendee, CommonName = commonName }; + AttendeeProperty a = new() { Value = attendee, CommonName = commonName }; base.Add(a); diff --git a/Source/EWSPDIData/PDIProperties/BaseAltRepProperty.cs b/Source/EWSPDIData/PDIProperties/BaseAltRepProperty.cs index 7cbc5b0..ff20a07 100644 --- a/Source/EWSPDIData/PDIProperties/BaseAltRepProperty.cs +++ b/Source/EWSPDIData/PDIProperties/BaseAltRepProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : BaseAltRepProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/18/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains an abstract base class used for the various iCalenar property classes that support the // Alternate Representation (ALTREP) parameter. @@ -20,7 +19,6 @@ //=============================================================================================================== using System; -using System.Globalization; using System.Text; namespace EWSoftware.PDI.Properties @@ -41,7 +39,7 @@ public abstract class BaseAltRepProperty : BaseProperty /// /// This parameter is only applicable to iCalendar 2.0 objects. It specifies a URI that points to /// an alternate representation for a textual property value. - public string AlternateRepresentation { get; set; } + public string? AlternateRepresentation { get; set; } #endregion @@ -100,6 +98,7 @@ public override void DeserializeParameters(StringCollection parameters) return; for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) + { if(String.Compare(parameters[paramIdx], "ALTREP=", StringComparison.OrdinalIgnoreCase) == 0) { // Remove the parameter name @@ -114,6 +113,7 @@ public override void DeserializeParameters(StringCollection parameters) } break; } + } // Let the base class handle all other parameters base.DeserializeParameters(parameters); diff --git a/Source/EWSPDIData/PDIProperties/BaseDateTimeProperty.cs b/Source/EWSPDIData/PDIProperties/BaseDateTimeProperty.cs index 8e22589..dbae44a 100644 --- a/Source/EWSPDIData/PDIProperties/BaseDateTimeProperty.cs +++ b/Source/EWSPDIData/PDIProperties/BaseDateTimeProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : BaseDateTimeProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 05/17/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains an abstract base date/time property class used to create the other date/time property // classes. @@ -40,7 +39,7 @@ public abstract class BaseDateTimeProperty : BaseProperty //===================================================================== private DateTime propDate; - private string timeZoneId; + private string? timeZoneId; #endregion @@ -68,7 +67,7 @@ public abstract class BaseDateTimeProperty : BaseProperty /// value, the time part of the property value is considered to be expressed in local time for the given /// time zone rather than universal time. The ID should match a time zone ID on a VTIMEZONE component in /// the owning calendar. If set, the property is ignored. - public string TimeZoneId + public string? TimeZoneId { get => timeZoneId; set @@ -84,7 +83,7 @@ public string TimeZoneId /// This is used to get or set the calendar scale (CALSCALE) parameter value /// /// This property is only applicable to vCard 4.0 date/time objects - public string CalendarScale { get; set; } + public string? CalendarScale { get; set; } /// /// This is used to get or set the value as a object expressed in the @@ -171,7 +170,7 @@ public virtual DateTime DateTimeValue /// /// This property is overridden to handle parsing the date/time to/from its string form /// - public override string Value + public override string? Value { get { @@ -254,7 +253,7 @@ public override string Value /// /// This property is overridden to handle parsing the date/time to/from its string form /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -305,7 +304,7 @@ public override void SerializeParameters(StringBuilder sb) sb.Append(ParameterNames.TimeZoneId); sb.Append('='); - if(timeZoneId.IndexOfAny(new char[] { ',', ';', ':' }) != -1) + if(timeZoneId.IndexOfAny([',', ';', ':']) != -1) { sb.Append('\"'); sb.Append(timeZoneId); diff --git a/Source/EWSPDIData/PDIProperties/BaseProperty.cs b/Source/EWSPDIData/PDIProperties/BaseProperty.cs index 6aa9b63..f78bec0 100644 --- a/Source/EWSPDIData/PDIProperties/BaseProperty.cs +++ b/Source/EWSPDIData/PDIProperties/BaseProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : BaseProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/18/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the base property class used by the Personal Data Interchange (PDI) classes such as // vCalendar, iCalendar, and vCard. @@ -37,42 +37,43 @@ public abstract class BaseProperty : PDIObject #region Private data members //===================================================================== - private string propValue, // The value of the property - encMethod, // The encoding method used on the property value - charSet, // The character set used for the property value - language, // The language used for the property value + private string encMethod = null!, // The encoding method used on the property value + charSet = null!, // The character set used for the property value + language = null!; // The language used for the property value + private string? propValue, // The value of the property location; // The data type/location of the property value private EncodingType encType; // This is kept in sync with encMethod // This is used to map parameter name and value strings to a ParameterType enumeration - private static NameToValue[] ntv = { - new NameToValue(ParameterNames.Encoding, ParameterType.Encoding), - new NameToValue(ParameterNames.CharacterSet, ParameterType.CharacterSet), - new NameToValue(ParameterNames.Language, ParameterType.Language), - new NameToValue(ParameterNames.ValueLocation, ParameterType.ValueLocation), - new NameToValue(ParameterNames.PropertyId, ParameterType.PropertyId), - new NameToValue(EncodingValue.SevenBit, ParameterType.Encoding, true), - new NameToValue(EncodingValue.EightBit, ParameterType.Encoding, true), - new NameToValue(EncodingValue.QuotedPrintable, ParameterType.Encoding, true), - new NameToValue(EncodingValue.Base64, ParameterType.Encoding, true), - new NameToValue(EncodingValue.BEncoding, ParameterType.Encoding, true), - new NameToValue(CharSetValue.ASCII, ParameterType.CharacterSet, true), - new NameToValue(LanguageValue.USEnglish, ParameterType.Language, true), - new NameToValue(ValLocValue.Inline, ParameterType.ValueLocation, true), - new NameToValue(ValLocValue.Text, ParameterType.ValueLocation, true), - new NameToValue(ValLocValue.Date, ParameterType.ValueLocation, true), - new NameToValue(ValLocValue.DateTime, ParameterType.ValueLocation, true), - new NameToValue(ValLocValue.Binary, ParameterType.ValueLocation, true), - new NameToValue(ValLocValue.Url, ParameterType.ValueLocation, true), - new NameToValue(ValLocValue.Uri, ParameterType.ValueLocation, true), - new NameToValue(ValLocValue.ContentId, ParameterType.ValueLocation, true), - new NameToValue(ValLocValue.Cid, ParameterType.ValueLocation, true), + private static readonly NameToValue[] ntv = + [ + new(ParameterNames.Encoding, ParameterType.Encoding), + new(ParameterNames.CharacterSet, ParameterType.CharacterSet), + new(ParameterNames.Language, ParameterType.Language), + new(ParameterNames.ValueLocation, ParameterType.ValueLocation), + new(ParameterNames.PropertyId, ParameterType.PropertyId), + new(EncodingValue.SevenBit, ParameterType.Encoding, true), + new(EncodingValue.EightBit, ParameterType.Encoding, true), + new(EncodingValue.QuotedPrintable, ParameterType.Encoding, true), + new(EncodingValue.Base64, ParameterType.Encoding, true), + new(EncodingValue.BEncoding, ParameterType.Encoding, true), + new(CharSetValue.ASCII, ParameterType.CharacterSet, true), + new(LanguageValue.USEnglish, ParameterType.Language, true), + new(ValLocValue.Inline, ParameterType.ValueLocation, true), + new(ValLocValue.Text, ParameterType.ValueLocation, true), + new(ValLocValue.Date, ParameterType.ValueLocation, true), + new(ValLocValue.DateTime, ParameterType.ValueLocation, true), + new(ValLocValue.Binary, ParameterType.ValueLocation, true), + new(ValLocValue.Url, ParameterType.ValueLocation, true), + new(ValLocValue.Uri, ParameterType.ValueLocation, true), + new(ValLocValue.ContentId, ParameterType.ValueLocation, true), + new(ValLocValue.Cid, ParameterType.ValueLocation, true), // The last entry should always be Custom to catch all unrecognized parameters. The actual property // name is not relevant. new NameToValue("X-", ParameterType.Custom) - }; + ]; #endregion #region Properties @@ -118,8 +119,10 @@ public override SpecificationVersions Version this.EncodingMethod = EncodingType.BEncoding; } else + { if(this.EncodingMethod == EncodingType.BEncoding) this.EncodingMethod = EncodingType.Base64; + } } } @@ -129,7 +132,7 @@ public override SpecificationVersions Version /// vCard properties support grouping. If grouped, this property will contain the name of the /// group with which it is associated. This property is ignored for vCalendar and iCalendar /// properties. - public string Group { get; set; } + public string? Group { get; set; } /// /// Set or get the encoding method for this property's value as a string @@ -265,7 +268,7 @@ public string Language /// /// This is only valid for vCard 4.0 objects. There may be a single value or multiple values /// separated by commas. It is up to the user to decode and make use of these values. - public string PropertyId { get; set; } + public string? PropertyId { get; set; } /// /// The value (data) type or location of this property's value @@ -277,7 +280,7 @@ public string Language /// /// If necessary, the encoding method is reset to an appropriate setting based on the new /// location/type (i.e. Base64 for binary, 7-bit for non-binary data, etc). - public string ValueLocation + public string? ValueLocation { get => location ?? this.DefaultValueLocation; set @@ -306,7 +309,7 @@ public string ValueLocation /// The parameters are returned in a string containing each parameter and its value separated by /// semi-colons (i.e. "X-ABC-Custom1=Value;X-ABC-Custom2=3". It is up to the caller to determine what to /// do with them. It can be overridden in derived classes to alter its behavior. - public virtual string CustomParameters { get; set; } + public virtual string? CustomParameters { get; set; } /// /// This is used to set or get the value of the property in its unencoded string form @@ -322,7 +325,7 @@ public string ValueLocation /// Derived classes can override this to parse the value and provide access to it via type-specific /// value properties. If this property is overridden, override EncodedValue as well to ensure the /// value is stored correctly in either form. - public virtual string Value + public virtual string? Value { get => propValue; set => propValue = value; @@ -346,7 +349,7 @@ public virtual string Value /// /// If this property is overridden, override Value as well to ensure the value is stored /// correctly in either form. - public virtual string EncodedValue + public virtual string? EncodedValue { get { @@ -368,9 +371,9 @@ public virtual string EncodedValue /// protected BaseProperty() { - this.CharacterSet = null; - this.Language = null; - this.EncodingString = null; + this.CharacterSet = null!; + this.Language = null!; + this.EncodingString = null!; this.ValueLocation = null; } #endregion @@ -448,9 +451,10 @@ protected override void Clone(PDIObject p) /// directly to the TextWriter as they may need to manipulate the string to fold lines, etc. /// This is thrown if the StringBuilder parameter is null and the /// TextWriter is not a StringWriter. - public static void WriteToStream(BaseProperty prop, StringBuilder sb, TextWriter tw) + public static void WriteToStream(BaseProperty? prop, StringBuilder? sb, TextWriter tw) { if(prop != null) + { if(sb != null) { sb.Length = 0; @@ -461,6 +465,7 @@ public static void WriteToStream(BaseProperty prop, StringBuilder sb, TextWriter } else prop.ToString(((StringWriter)tw).GetStringBuilder()); + } } /// @@ -470,12 +475,12 @@ public static void WriteToStream(BaseProperty prop, StringBuilder sb, TextWriter /// Returns true if the object equals this instance, false if it does not public override bool Equals(object obj) { - if(!(obj is BaseProperty bp)) + if(obj is not BaseProperty bp) return false; // The ToString() method returns a text representation of the property based on all of its settings // so it's a reliable way to tell if two instances are the same. - return (this == bp || this.ToString() == bp.ToString()); + return this == bp || this.ToString() == bp.ToString(); } /// @@ -500,7 +505,7 @@ public override int GetHashCode() /// There are two overloads for this method public sealed override string ToString() { - StringBuilder sb = new StringBuilder(256); + StringBuilder sb = new(256); // Let the derived class format the rest of the property this.ToString(sb); @@ -523,7 +528,7 @@ public void ToString(StringBuilder sb) int priorLength, length; // If the value is null or empty, don't add it - string encVal = this.EncodedValue; + string? encVal = this.EncodedValue; if(encVal == null || encVal.Length == 0) return; @@ -778,7 +783,7 @@ public virtual void DeserializeParameters(StringCollection parameters) if(parameters == null || parameters.Count == 0) return; - StringBuilder sb = new StringBuilder(80); + StringBuilder sb = new(80); for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) { @@ -844,7 +849,7 @@ public virtual void DeserializeParameters(StringCollection parameters) } // If it contains a semi-colon, colon, or comma, enclose the value in quotes - if(parameters[paramIdx].IndexOfAny(new[] { ',', ';', ':' }) != -1) + if(parameters[paramIdx].IndexOfAny([',', ';', ':']) != -1) { sb.Append('\"'); sb.Append(parameters[paramIdx]); @@ -873,14 +878,16 @@ public virtual void DeserializeParameters(StringCollection parameters) /// For vCard 2.1 and vCalendar 1.0 properties, if a parameter has been /// specified, the value is converted from the one specified by the /// property to the one specified by the CharacterSet property before encoding it. - public virtual string Encode(string data) + public virtual string? Encode(string? data) { - string encoded; + string? encoded; // It's only done if the value is inline, text, or binary if(this.ValueLocation != ValLocValue.Inline && this.ValueLocation != ValLocValue.Text && this.ValueLocation != ValLocValue.Binary) + { return data; + } if((this.Version == SpecificationVersions.vCard21 || this.Version == SpecificationVersions.vCalendar10) && String.Compare(this.CharacterSet, CharSetValue.ASCII, StringComparison.OrdinalIgnoreCase) != 0) @@ -890,7 +897,7 @@ public virtual string Encode(string data) // Use the literal bytes. If we get the string, the encoder gives us the decoded values which is // not what we want to write out. - StringBuilder sb = new StringBuilder(destBytes.Length); + StringBuilder sb = new(destBytes.Length); for(int nIdx = 0; nIdx < destBytes.Length; nIdx++) sb.Append((char)destBytes[nIdx]); @@ -905,19 +912,19 @@ public virtual string Encode(string data) // Escape characters for these if necessary. vCard 2.1 and vCalendar 1.0 do not escape // commas and semi-colons. if(this.Version == SpecificationVersions.vCard21 || this.Version == SpecificationVersions.vCalendar10) - encoded = EncodingUtils.RestrictedEscape(data); + encoded = EncodingUtils.RestrictedEscape(data)!; else - encoded = EncodingUtils.Escape(data); + encoded = EncodingUtils.Escape(data)!; break; case EncodingType.QuotedPrintable: - encoded = EncodingUtils.ToQuotedPrintable(data, 75); + encoded = EncodingUtils.ToQuotedPrintable(data, 75)!; break; case EncodingType.Base64: case EncodingType.BEncoding: // Base 64 encoding - encoded = EncodingUtils.ToBase64(data, 75, (this.EncodingMethod == EncodingType.Base64)); + encoded = EncodingUtils.ToBase64(data, 75, this.EncodingMethod == EncodingType.Base64)!; break; default: // Custom, can't do anything with it @@ -941,14 +948,16 @@ public virtual string Encode(string data) /// For vCard 2.1 and vCalendar 1.0 properties, if a parameter has been /// specified, the value is converted from the specified character set to the one specified by the /// property after decoding. - public virtual string Decode(string data) + public virtual string? Decode(string? data) { - string decoded; + string? decoded; // It's only done if the value is inline, text, or binary if(this.ValueLocation != ValLocValue.Inline && this.ValueLocation != ValLocValue.Text && this.ValueLocation != ValLocValue.Binary) + { return data; + } switch(this.EncodingMethod) { diff --git a/Source/EWSPDIData/PDIProperties/BirthDateProperty.cs b/Source/EWSPDIData/PDIProperties/BirthDateProperty.cs index 0c8b01b..376f9b0 100644 --- a/Source/EWSPDIData/PDIProperties/BirthDateProperty.cs +++ b/Source/EWSPDIData/PDIProperties/BirthDateProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : BirthDateProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Birth Date property class used by the Personal Data Interchange (PDI) vCard classes // @@ -70,7 +69,7 @@ public BirthDateProperty() /// A clone of the object public override object Clone() { - BirthDateProperty o = new BirthDateProperty(); + BirthDateProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/BodyProperty.cs b/Source/EWSPDIData/PDIProperties/BodyProperty.cs index 3128094..21c85e2 100644 --- a/Source/EWSPDIData/PDIProperties/BodyProperty.cs +++ b/Source/EWSPDIData/PDIProperties/BodyProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : BodyProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2007-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2007-2025, Eric Woodruff, All rights reserved // // This file contains the Body property. It is used with the Personal Data Interchange (PDI) vNote class. // @@ -69,7 +68,7 @@ public BodyProperty() /// A clone of the object public override object Clone() { - BodyProperty o = new BodyProperty(); + BodyProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/CalendarScaleProperty.cs b/Source/EWSPDIData/PDIProperties/CalendarScaleProperty.cs index 24390e1..290b6d2 100644 --- a/Source/EWSPDIData/PDIProperties/CalendarScaleProperty.cs +++ b/Source/EWSPDIData/PDIProperties/CalendarScaleProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : CalendarScaleProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Calendar Scale property used by the Personal Data Interchange (PDI) iCalendar classes // @@ -71,7 +70,7 @@ public CalendarScaleProperty() /// A clone of the object public override object Clone() { - CalendarScaleProperty o = new CalendarScaleProperty(); + CalendarScaleProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/CategoriesProperty.cs b/Source/EWSPDIData/PDIProperties/CategoriesProperty.cs index 3b09b7c..0298b6c 100644 --- a/Source/EWSPDIData/PDIProperties/CategoriesProperty.cs +++ b/Source/EWSPDIData/PDIProperties/CategoriesProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : CategoriesProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Categories property class used by the Personal Data Interchange (PDI) classes such as // vCalendar, iCalendar, and vCard. @@ -38,9 +37,9 @@ public class CategoriesProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reSplit = new Regex(@"(?:^[,;])|(?<=(?:[^\\]))[,;]"); + private static readonly Regex reSplit = new(@"(?:^[,;])|(?<=(?:[^\\]))[,;]"); - private StringCollection categories; + private readonly StringCollection categories; #endregion @@ -80,18 +79,15 @@ public string CategoriesString get => String.Join(", ", categories); set { - string tempCat; - string[] entries; - categories.Clear(); if(value != null) { - entries = value.Split(',', ';'); + string[] entries = value.Split(',', ';'); foreach(string s in entries) { - tempCat = s.Trim(); + string tempCat = s.Trim(); if(tempCat.Length > 0) categories.Add(tempCat); @@ -104,7 +100,7 @@ public string CategoriesString /// This property is overridden to handle parsing the categories and concatenating them when requested /// /// The categories are escaped as needed - public override string Value + public override string? Value { get { @@ -112,7 +108,7 @@ public override string Value if(this.Categories.Count == 0) return null; - StringBuilder sb = new StringBuilder(256); + StringBuilder sb = new(256); foreach(string s in this.Categories) { @@ -131,22 +127,19 @@ public override string Value } set { - string tempCat; - string[] entries; - this.Categories.Clear(); if(value != null && value.Length > 0) { // Split on all semi-colons and commas except escaped ones - entries = reSplit.Split(value); + string[] entries = reSplit.Split(value); foreach(string s in entries) { - tempCat = EncodingUtils.Unescape(s.Trim()); + string? tempCat = EncodingUtils.Unescape(s.Trim()); - if(tempCat.Length > 0) - categories.Add(tempCat); + if((tempCat?.Length ?? 0) > 0) + categories.Add(tempCat!); } } } @@ -156,7 +149,7 @@ public override string Value /// This property is overridden to handle parsing the categories and concatenating them when requested /// /// The categories are escaped as needed - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -173,7 +166,7 @@ public override string EncodedValue public CategoriesProperty() { this.Version = SpecificationVersions.iCalendar20; - categories = new StringCollection(); + categories = []; } #endregion @@ -186,7 +179,7 @@ public CategoriesProperty() /// A clone of the object public override object Clone() { - CategoriesProperty o = new CategoriesProperty(); + CategoriesProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/ClassificationProperty.cs b/Source/EWSPDIData/PDIProperties/ClassificationProperty.cs index b5c986f..39de6e0 100644 --- a/Source/EWSPDIData/PDIProperties/ClassificationProperty.cs +++ b/Source/EWSPDIData/PDIProperties/ClassificationProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ClassificationProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains Classification property class used by the Personal Data Interchange (PDI) classes such as // vCalendar, iCalendar, and vCard. @@ -76,7 +75,7 @@ public ClassificationProperty() /// A clone of the object public override object Clone() { - ClassificationProperty o = new ClassificationProperty(); + ClassificationProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/ClientPidMapProperty.cs b/Source/EWSPDIData/PDIProperties/ClientPidMapProperty.cs index d6e5d48..4b62479 100644 --- a/Source/EWSPDIData/PDIProperties/ClientPidMapProperty.cs +++ b/Source/EWSPDIData/PDIProperties/ClientPidMapProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : ClientPidMapProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/20/2019 -// Note : Copyright 2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2019-2025, Eric Woodruff, All rights reserved // // This file contains the Client PID Map property class used by the Personal Data Interchange (PDI) vCard class // @@ -56,12 +56,12 @@ public class ClientPidMapProperty : BaseProperty /// /// This is used to get or set the URI /// - public string Uri { get; set; } + public string? Uri { get; set; } /// /// This property is overridden to handle parsing the component parts to/from their string form /// - public override string Value + public override string? Value { get { @@ -77,7 +77,7 @@ public override string Value if(!String.IsNullOrWhiteSpace(value)) { - string[] parts = value.Split(';'); + string[] parts = value!.Split(';'); if(parts[0].Length != 0 && Int32.TryParse(parts[0], out int id) && id != 0) this.Id = id; @@ -91,7 +91,7 @@ public override string Value /// /// This property is overridden to handle parsing the component parts to/from their string form /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; diff --git a/Source/EWSPDIData/PDIProperties/CommentProperty.cs b/Source/EWSPDIData/PDIProperties/CommentProperty.cs index 4e51968..ab3a8a3 100644 --- a/Source/EWSPDIData/PDIProperties/CommentProperty.cs +++ b/Source/EWSPDIData/PDIProperties/CommentProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : CommentProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Comment property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -72,7 +71,7 @@ public CommentProperty() /// A clone of the object public override object Clone() { - CommentProperty o = new CommentProperty(); + CommentProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/CompletedDateProperty.cs b/Source/EWSPDIData/PDIProperties/CompletedDateProperty.cs index 35e5893..8d24201 100644 --- a/Source/EWSPDIData/PDIProperties/CompletedDateProperty.cs +++ b/Source/EWSPDIData/PDIProperties/CompletedDateProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : CompletedDateProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Completed Date property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -57,7 +56,7 @@ public class CompletedDateProperty : BaseDateTimeProperty /// /// This property does not allow a time zone and is always a UTC date/time value /// - public override string Value + public override string? Value { get { @@ -96,7 +95,7 @@ public CompletedDateProperty() /// A clone of the object public override object Clone() { - CompletedDateProperty o = new CompletedDateProperty(); + CompletedDateProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/ContactProperty.cs b/Source/EWSPDIData/PDIProperties/ContactProperty.cs index 601c453..5765bbc 100644 --- a/Source/EWSPDIData/PDIProperties/ContactProperty.cs +++ b/Source/EWSPDIData/PDIProperties/ContactProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ContactProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Contact property. It is used with the iCalendar Personal Data Interchange (PDI) // classes. @@ -72,7 +71,7 @@ public ContactProperty() /// A clone of the object public override object Clone() { - ContactProperty o = new ContactProperty(); + ContactProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/ContactPropertyCollection.cs b/Source/EWSPDIData/PDIProperties/ContactPropertyCollection.cs index e35cbbf..2449720 100644 --- a/Source/EWSPDIData/PDIProperties/ContactPropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/ContactPropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ContactPropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for ContactProperty objects. It is used with the iCalendar Personal // Data Interchange (PDI) classes. @@ -63,7 +62,7 @@ public ContactPropertyCollection(IList contacts) : base(contact /// Returns the new property that was created and added to the collection public ContactProperty Add(string contact) { - ContactProperty c = new ContactProperty { Value = contact }; + ContactProperty c = new() { Value = contact }; base.Add(c); diff --git a/Source/EWSPDIData/PDIProperties/CustomProperty.cs b/Source/EWSPDIData/PDIProperties/CustomProperty.cs index 6e16b61..f7764a2 100644 --- a/Source/EWSPDIData/PDIProperties/CustomProperty.cs +++ b/Source/EWSPDIData/PDIProperties/CustomProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : CustomProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the custom property class. It is used with the Personal Data Interchange (PDI) classes // such as vCalendar, iCalendar, and vCard to contain non-standard property names and values. @@ -34,7 +33,7 @@ public class CustomProperty : BaseProperty #region Private data members //===================================================================== - private string customName; + private string customName = null!; #endregion @@ -86,7 +85,7 @@ public string CustomName /// /// Since we don't know what it is, we may not be able to tell if it's encoded or not. It will /// get passed through unchanged. - public override string EncodedValue + public override string? EncodedValue { get => base.Value; set => base.Value = value; @@ -123,7 +122,7 @@ public CustomProperty(string propertyName) /// A clone of the object public override object Clone() { - CustomProperty o = new CustomProperty(customName); + CustomProperty o = new(customName); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/CustomPropertyCollection.cs b/Source/EWSPDIData/PDIProperties/CustomPropertyCollection.cs index 79486a4..507a943 100644 --- a/Source/EWSPDIData/PDIProperties/CustomPropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/CustomPropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : CustomProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for CustomProperty objects. It is used with the Personal Data // Interchange (PDI) classes such as vCalendar, iCalendar, and vCard. @@ -65,24 +64,28 @@ public CustomPropertyCollection(IList customProps) : base(custom /// This is thrown if an attempt is made to set an item using a name /// that does not exist in the collection. /// The property name is case-insensitive - public CustomProperty this[string propertyName] + public CustomProperty? this[string propertyName] { get { for(int idx = 0; idx < base.Count; idx++) + { if(String.Compare(base[idx].Tag, propertyName, StringComparison.OrdinalIgnoreCase) == 0) return base[idx]; + } return null; } set { for(int idx = 0; idx < base.Count; idx++) + { if(String.Compare(base[idx].Tag, propertyName, StringComparison.OrdinalIgnoreCase) == 0) { - base[idx] = value; + base[idx] = value!; return; } + } throw new ArgumentException(LR.GetString("ExCPropIDNotFound")); } @@ -100,7 +103,7 @@ public CustomProperty this[string propertyName] /// Returns the newly created custom property public CustomProperty Add(string tag, string propertyValue) { - CustomProperty cprop = new CustomProperty(tag) { Value = propertyValue }; + CustomProperty cprop = new(tag) { Value = propertyValue }; base.Add(cprop); diff --git a/Source/EWSPDIData/PDIProperties/DateCreatedProperty.cs b/Source/EWSPDIData/PDIProperties/DateCreatedProperty.cs index b9dba29..e55cb87 100644 --- a/Source/EWSPDIData/PDIProperties/DateCreatedProperty.cs +++ b/Source/EWSPDIData/PDIProperties/DateCreatedProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : DateCreatedProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Date Created property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -67,7 +66,7 @@ public override string Tag /// /// This property does not allow a time zone and is always a UTC date/time value /// - public override string Value + public override string? Value { get { @@ -105,7 +104,7 @@ public DateCreatedProperty() /// A clone of the object public override object Clone() { - DateCreatedProperty o = new DateCreatedProperty(); + DateCreatedProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/DaylightProperty.cs b/Source/EWSPDIData/PDIProperties/DaylightProperty.cs index 7250556..1a0d650 100644 --- a/Source/EWSPDIData/PDIProperties/DaylightProperty.cs +++ b/Source/EWSPDIData/PDIProperties/DaylightProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : DaylightProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Daylight property used by the Personal Data Interchange (PDI) vCalendar classes // @@ -78,21 +77,21 @@ public class DaylightProperty : BaseProperty /// /// This is used to get or set the standard time designation (i.e. PST, EST) /// - public string StandardDesignation { get; set; } + public string? StandardDesignation { get; set; } /// /// This is used to get or set the daylight saving time designation (i.e. PDT, EDT) /// - public string DaylightDesignation { get; set; } + public string? DaylightDesignation { get; set; } /// /// This property is overridden to handle parsing the components and concatenating them when requested /// - public override string Value + public override string? Value { get { - string[] parts = new string[6]; + string?[] parts = new string[6]; // If false, don't bother if(!this.UsesDaylightSavingTime) @@ -159,7 +158,7 @@ public override string Value /// /// This property is overridden to handle parsing the components and concatenating them when requested /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -187,7 +186,7 @@ public DaylightProperty() /// A clone of the object public override object Clone() { - DaylightProperty o = new DaylightProperty(); + DaylightProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/DescriptionProperty.cs b/Source/EWSPDIData/PDIProperties/DescriptionProperty.cs index 0bf3d70..44c78e1 100644 --- a/Source/EWSPDIData/PDIProperties/DescriptionProperty.cs +++ b/Source/EWSPDIData/PDIProperties/DescriptionProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : DescriptionProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Description property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -74,7 +73,7 @@ public DescriptionProperty() /// A clone of the object public override object Clone() { - DescriptionProperty o = new DescriptionProperty(); + DescriptionProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/DueDateProperty.cs b/Source/EWSPDIData/PDIProperties/DueDateProperty.cs index 9aec829..ff316e9 100644 --- a/Source/EWSPDIData/PDIProperties/DueDateProperty.cs +++ b/Source/EWSPDIData/PDIProperties/DueDateProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : DueDateProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Due Date property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -73,7 +72,7 @@ public DueDateProperty() /// A clone of the object public override object Clone() { - DueDateProperty o = new DueDateProperty(); + DueDateProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/DurationProperty.cs b/Source/EWSPDIData/PDIProperties/DurationProperty.cs index f8ac546..82ac76a 100644 --- a/Source/EWSPDIData/PDIProperties/DurationProperty.cs +++ b/Source/EWSPDIData/PDIProperties/DurationProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : DurationProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Duration property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -61,7 +60,7 @@ public class DurationProperty : BaseProperty /// /// Due to the variable nature of the definition of months and years, the value is always returned /// with the maximum unit of time expressed in weeks if needed. - public override string Value + public override string? Value { get { @@ -77,7 +76,7 @@ public override string Value /// /// This property is overridden to handle converting the text value to a duration object /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -105,7 +104,7 @@ public DurationProperty() /// A clone of the object public override object Clone() { - DurationProperty o = new DurationProperty(); + DurationProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/EMailProperty.cs b/Source/EWSPDIData/PDIProperties/EMailProperty.cs index a44b070..6c2a0fb 100644 --- a/Source/EWSPDIData/PDIProperties/EMailProperty.cs +++ b/Source/EWSPDIData/PDIProperties/EMailProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : EMailProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/16/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the e-mail property class. It is used with the Personal Data Interchange (PDI) vCard // class. @@ -40,25 +40,26 @@ public class EMailProperty : BaseProperty #region Private data members //===================================================================== - private static readonly Regex reSplit = new Regex(@"(?:^[,])|(?<=(?:[^\\]))[,]"); + private static readonly Regex reSplit = new(@"(?:^[,])|(?<=(?:[^\\]))[,]"); // This private array is used to translate parameter names and values to email types - private static readonly NameToValue[] ntv = { - new NameToValue("TYPE", EMailTypes.None, false), - new NameToValue("PREF", EMailTypes.Preferred, true), - new NameToValue("AOL", EMailTypes.AOL, true), - new NameToValue("AppleLink", EMailTypes.AppleLink, true), - new NameToValue("ATTMail", EMailTypes.ATTMail, true), - new NameToValue("CIS", EMailTypes.CompuServe, true), - new NameToValue("eWorld", EMailTypes.eWorld, true), - new NameToValue("INTERNET", EMailTypes.Internet, true), - new NameToValue("IBMMail", EMailTypes.IBMMail, true), - new NameToValue("MCIMail", EMailTypes.MCIMail, true), - new NameToValue("POWERSHARE", EMailTypes.PowerShare, true), - new NameToValue("PRODIGY", EMailTypes.Prodigy, true), - new NameToValue("TLX", EMailTypes.Telex, true), - new NameToValue("X400", EMailTypes.X400, true) - }; + private static readonly NameToValue[] ntv = + [ + new("TYPE", EMailTypes.None, false), + new("PREF", EMailTypes.Preferred, true), + new("AOL", EMailTypes.AOL, true), + new("AppleLink", EMailTypes.AppleLink, true), + new("ATTMail", EMailTypes.ATTMail, true), + new("CIS", EMailTypes.CompuServe, true), + new("eWorld", EMailTypes.eWorld, true), + new("INTERNET", EMailTypes.Internet, true), + new("IBMMail", EMailTypes.IBMMail, true), + new("MCIMail", EMailTypes.MCIMail, true), + new("POWERSHARE", EMailTypes.PowerShare, true), + new("PRODIGY", EMailTypes.Prodigy, true), + new("TLX", EMailTypes.Telex, true), + new("X400", EMailTypes.X400, true) + ]; private short preferredOrder; @@ -131,7 +132,7 @@ public EMailProperty() /// A clone of the object public override object Clone() { - EMailProperty o = new EMailProperty(); + EMailProperty o = new(); o.Clone(this); return o; } @@ -175,9 +176,10 @@ public override void SerializeParameters(StringBuilder sb) // Serialize the e-mail types if necessary if(parameterValue != EMailTypes.None && parameterValue != EMailTypes.Internet) { - StringBuilder sbTypes = new StringBuilder(50); + StringBuilder sbTypes = new(50); for(int idx = 1; idx < ntv.Length; idx++) + { if((parameterValue & ntv[idx].EnumValue) != 0) { if(sbTypes.Length > 0) @@ -185,6 +187,7 @@ public override void SerializeParameters(StringBuilder sb) sbTypes.Append(ntv[idx].Name); } + } // The format is different for the 3.0 and later specs if(this.Version == SpecificationVersions.vCard21) @@ -245,8 +248,10 @@ public override void DeserializeParameters(StringCollection parameters) foreach(string s in types) { for(subIdx = 1; subIdx < ntv.Length; subIdx++) + { if(ntv[subIdx].IsMatch(s)) break; + } // Unrecognized ones are ignored if(subIdx < ntv.Length) diff --git a/Source/EWSPDIData/PDIProperties/EMailPropertyCollection.cs b/Source/EWSPDIData/PDIProperties/EMailPropertyCollection.cs index ca093f8..4ecf613 100644 --- a/Source/EWSPDIData/PDIProperties/EMailPropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/EMailPropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : EMailPropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for EMailProperty objects. It is used with the Personal Data // Interchange (PDI) vCard class. @@ -64,9 +63,9 @@ public EMailPropertyCollection(IList emailAddresses) : base(email /// Returns the new property that was created and added to the collection public EMailProperty Add(string email) { - EMailProperty e = new EMailProperty { Value = email }; + EMailProperty e = new() { Value = email }; - base.Add(e); + this.Add(e); return e; } @@ -79,9 +78,9 @@ public EMailProperty Add(string email) /// Returns the new property that was created and added to the collection public EMailProperty Add(EMailTypes emailTypes, string email) { - EMailProperty e = new EMailProperty { EMailTypes = emailTypes, Value = email }; + EMailProperty e = new() { EMailTypes = emailTypes, Value = email }; - base.Add(e); + this.Add(e); return e; } @@ -147,14 +146,16 @@ public void SetPreferred(int idx) /// the one with the Preferred flag set. If a preferred e-mail address with one of the given /// types cannot be found, it will return the first e-mail address matching one of the given types /// without the Preferred flag set. If no e-mail address can be found, it returns null. - public EMailProperty FindFirstByType(EMailTypes emailType) + public EMailProperty? FindFirstByType(EMailTypes emailType) { EMailTypes emailNoPref = emailType & ~EMailTypes.Preferred; bool usePreferred = (emailNoPref != emailType); foreach(EMailProperty email in this) + { if((email.EMailTypes & emailNoPref) != 0 && (!usePreferred || (email.EMailTypes & EMailTypes.Preferred) != 0)) return email; + } // Try again without the preferred flag? if(usePreferred) diff --git a/Source/EWSPDIData/PDIProperties/EndDateProperty.cs b/Source/EWSPDIData/PDIProperties/EndDateProperty.cs index b5e13d6..afccf6d 100644 --- a/Source/EWSPDIData/PDIProperties/EndDateProperty.cs +++ b/Source/EWSPDIData/PDIProperties/EndDateProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : EndDateProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the End Date property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -74,7 +73,7 @@ public EndDateProperty() /// A clone of the object public override object Clone() { - EndDateProperty o = new EndDateProperty(); + EndDateProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/ExDateProperty.cs b/Source/EWSPDIData/PDIProperties/ExDateProperty.cs index c73c6f8..7ec5312 100644 --- a/Source/EWSPDIData/PDIProperties/ExDateProperty.cs +++ b/Source/EWSPDIData/PDIProperties/ExDateProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ExDateProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Exception Date property class used by the Personal Data Interchange (PDI) vCalendar // and iCalendar classes. @@ -74,7 +73,7 @@ public ExDateProperty() /// A clone of the object public override object Clone() { - ExDateProperty o = new ExDateProperty(); + ExDateProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/ExDatePropertyCollection.cs b/Source/EWSPDIData/PDIProperties/ExDatePropertyCollection.cs index b6f0ee5..7fc1cf4 100644 --- a/Source/EWSPDIData/PDIProperties/ExDatePropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/ExDatePropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ExDatePropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for ExDateProperty objects. It is used by the Personal Data // Interchange (PDI) vCalendar and iCalendar classes. @@ -64,9 +63,9 @@ public ExDatePropertyCollection(IList exDates) : base(exDates) /// Returns the new property that was created and added to the collection public ExDateProperty Add(DateTime dt) { - ExDateProperty exd = new ExDateProperty { DateTimeValue = dt }; + ExDateProperty exd = new() { DateTimeValue = dt }; - base.Add(exd); + this.Add(exd); return exd; } diff --git a/Source/EWSPDIData/PDIProperties/ExRuleProperty.cs b/Source/EWSPDIData/PDIProperties/ExRuleProperty.cs index caf369f..a01b5fe 100644 --- a/Source/EWSPDIData/PDIProperties/ExRuleProperty.cs +++ b/Source/EWSPDIData/PDIProperties/ExRuleProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ExRuleProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Exception Rule property. It is used with the Personal Data Interchange (PDI) // vCalendar and iCalendar classes. @@ -60,7 +59,7 @@ public ExRuleProperty() /// A clone of the object public override object Clone() { - ExRuleProperty o = new ExRuleProperty(); + ExRuleProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/FormattedNameProperty.cs b/Source/EWSPDIData/PDIProperties/FormattedNameProperty.cs index 1812919..d2abf3b 100644 --- a/Source/EWSPDIData/PDIProperties/FormattedNameProperty.cs +++ b/Source/EWSPDIData/PDIProperties/FormattedNameProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : FormattedNameProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Formatted Name property class used by the Personal Data Interchange (PDI) vCard class // @@ -55,11 +54,11 @@ public class FormattedNameProperty : BaseProperty /// specifications. /// This is thrown if an attempt is made to set this property to /// null. - public override string Value + public override string? Value { get { - string nameValue = base.Value; + string? nameValue = base.Value; if(String.IsNullOrWhiteSpace(nameValue)) return "Unknown"; @@ -76,11 +75,11 @@ public override string Value /// specifications. /// This is thrown if an attempt is made to set this property to /// null. - public override string EncodedValue + public override string? EncodedValue { get { - string nameValue = base.EncodedValue; + string? nameValue = base.EncodedValue; if(String.IsNullOrWhiteSpace(nameValue)) return "Unknown"; @@ -111,7 +110,7 @@ public FormattedNameProperty() /// A clone of the object public override object Clone() { - FormattedNameProperty o = new FormattedNameProperty(); + FormattedNameProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/FreeBusyProperty.cs b/Source/EWSPDIData/PDIProperties/FreeBusyProperty.cs index 9f89ca5..38486f2 100644 --- a/Source/EWSPDIData/PDIProperties/FreeBusyProperty.cs +++ b/Source/EWSPDIData/PDIProperties/FreeBusyProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : FreeBusyProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a class for the FREEBUSY property used by the Personal Data Interchange (PDI) VFreeBusy // class. @@ -21,7 +20,6 @@ using System; using System.ComponentModel; -using System.Globalization; using System.Text; using EWSoftware.PDI.Binding; @@ -40,9 +38,9 @@ public class FreeBusyProperty : BaseProperty #region Private data members //===================================================================== - private Period period; + private Period? period; private FreeBusyType freeBusyType; - private string otherType; + private string? otherType; #endregion @@ -90,7 +88,7 @@ public FreeBusyType FreeBusyType /// /// Setting this parameter automatically sets the property to /// Other. - public string OtherType + public string? OtherType { get => otherType; set @@ -122,7 +120,7 @@ public Period PeriodValue /// /// This property is overridden to handle parsing the period to/from its string form /// - public override string Value + public override string? Value { get { @@ -145,7 +143,7 @@ public override string Value /// /// This property is overridden to handle parsing the period to/from its string form /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -173,7 +171,7 @@ public FreeBusyProperty() /// A clone of the object public override object Clone() { - FreeBusyProperty o = new FreeBusyProperty(); + FreeBusyProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/FreeBusyPropertyCollection.cs b/Source/EWSPDIData/PDIProperties/FreeBusyPropertyCollection.cs index f6e7660..ae77048 100644 --- a/Source/EWSPDIData/PDIProperties/FreeBusyPropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/FreeBusyPropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : FreeBusyPropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for FreeBusyProperty objects. It is used by the Personal Data // Interchange (PDI) VFreeBusy class. @@ -65,9 +64,9 @@ public FreeBusyPropertyCollection(IList freeBusys) : base(free /// Returns the new property that was created and added to the collection public FreeBusyProperty Add(FreeBusyType type, Period p) { - FreeBusyProperty fb = new FreeBusyProperty { FreeBusyType = type, PeriodValue = p }; + FreeBusyProperty fb = new() { FreeBusyType = type, PeriodValue = p }; - base.Add(fb); + this.Add(fb); return fb; } diff --git a/Source/EWSPDIData/PDIProperties/GenderProperty.cs b/Source/EWSPDIData/PDIProperties/GenderProperty.cs index b54750c..788ef78 100644 --- a/Source/EWSPDIData/PDIProperties/GenderProperty.cs +++ b/Source/EWSPDIData/PDIProperties/GenderProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : GenderProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/20/2019 -// Note : Copyright 2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2019-2025, Eric Woodruff, All rights reserved // // This file contains the Gender property class used by the Personal Data Interchange (PDI) vCard class // @@ -30,6 +30,13 @@ namespace EWSoftware.PDI.Properties /// specification. public class GenderProperty : BaseProperty { + #region Private data members + //===================================================================== + + private static readonly char[] genderValues = ['M', 'F', 'O', 'N', 'U']; + + #endregion + #region Properties //===================================================================== @@ -57,12 +64,12 @@ public class GenderProperty : BaseProperty /// /// This is used to get or set the gender identity /// - public string GenderIdentity { get; set; } + public string? GenderIdentity { get; set; } /// /// This property is overridden to handle parsing the component parts to/from their string form /// - public override string Value + public override string? Value { get { @@ -81,13 +88,13 @@ public override string Value if(!String.IsNullOrWhiteSpace(value)) { - string[] parts = value.Split(';'); + string[] parts = value!.Split(';'); if(parts[0].Length != 0) { this.Sex = parts[0][0]; - if(!(new[] { 'M', 'F', 'O', 'N', 'U' }).Contains(this.Sex.Value)) + if(!(genderValues).Contains(this.Sex.Value)) this.Sex = null; } @@ -100,7 +107,7 @@ public override string Value /// /// This property is overridden to handle parsing the component parts to/from their string form /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; diff --git a/Source/EWSPDIData/PDIProperties/GeographicPositionProperty.cs b/Source/EWSPDIData/PDIProperties/GeographicPositionProperty.cs index 7860dfd..c59e618 100644 --- a/Source/EWSPDIData/PDIProperties/GeographicPositionProperty.cs +++ b/Source/EWSPDIData/PDIProperties/GeographicPositionProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : GeographicPositionProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 05/17/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // Compiler: Microsoft Visual C# // // This file contains Geographic Position property class used by the Personal Data Interchange (PDI) classes @@ -80,7 +80,7 @@ public class GeographicPositionProperty : BaseProperty /// /// This property is overridden to handle parsing the component parts to/from their string form /// - public override string Value + public override string? Value { get { @@ -105,7 +105,7 @@ public override string Value if(!String.IsNullOrWhiteSpace(value)) { - if(value.StartsWith("geo:", StringComparison.OrdinalIgnoreCase)) + if(value!.StartsWith("geo:", StringComparison.OrdinalIgnoreCase)) { this.IncludeGeoUriPrefix = true; value = value.Substring(4); @@ -113,7 +113,7 @@ public override string Value else this.IncludeGeoUriPrefix = false; - string[] parts = value.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); + string[] parts = value.Split([',', ';'], StringSplitOptions.RemoveEmptyEntries); if(parts.Length == 2) { @@ -127,7 +127,7 @@ public override string Value /// /// This property is overridden to handle parsing the component parts to/from their string form /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -157,7 +157,7 @@ public GeographicPositionProperty() /// A clone of the object public override object Clone() { - GeographicPositionProperty o = new GeographicPositionProperty(); + GeographicPositionProperty o = new(); o.Clone(this); return o; } @@ -175,7 +175,6 @@ protected override void Clone(PDIObject p) base.Clone(p); } - /// /// The specifications do not allow parameters for this property. Any parameters are ignored. /// diff --git a/Source/EWSPDIData/PDIProperties/KindProperty.cs b/Source/EWSPDIData/PDIProperties/KindProperty.cs index 0b9ab44..9e2c771 100644 --- a/Source/EWSPDIData/PDIProperties/KindProperty.cs +++ b/Source/EWSPDIData/PDIProperties/KindProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : KindProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/20/2019 -// Note : Copyright 2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2019-2025, Eric Woodruff, All rights reserved // // This file contains the kind property class used by the Personal Data Interchange (PDI) vCard class // @@ -33,7 +33,7 @@ public class KindProperty : BaseProperty //===================================================================== private CardKind cardKind; - private string otherKind; + private string? otherKind; #endregion @@ -71,8 +71,10 @@ public CardKind CardKind if(cardKind != CardKind.Other) otherKind = null; else + { if(String.IsNullOrWhiteSpace(otherKind)) otherKind = "X-UNKNOWN"; + } } } @@ -81,7 +83,7 @@ public CardKind CardKind /// /// Setting this parameter automatically sets the property to /// Other. - public string OtherKind + public string? OtherKind { get => otherKind; set @@ -99,11 +101,11 @@ public string OtherKind /// This property is overridden to handle converting the text value to a /// value. /// - public override string Value + public override string? Value { get { - string kind; + string? kind; switch(cardKind) { @@ -163,7 +165,7 @@ public override string Value /// This property is overridden to handle converting the text value to a /// value. /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -192,7 +194,7 @@ public KindProperty() /// A clone of the object public override object Clone() { - KindProperty o = new KindProperty(); + KindProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/LabelProperty.cs b/Source/EWSPDIData/PDIProperties/LabelProperty.cs index 42dba31..9ccf87a 100644 --- a/Source/EWSPDIData/PDIProperties/LabelProperty.cs +++ b/Source/EWSPDIData/PDIProperties/LabelProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : LabelProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Label property. It is used with the Personal Data Interchange (PDI) vCard class // @@ -39,19 +38,20 @@ public class LabelProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reSplit = new Regex(@"(?:^[,])|(?<=(?:[^\\]))[,]"); + private static readonly Regex reSplit = new(@"(?:^[,])|(?<=(?:[^\\]))[,]"); // This private array is used to translate parameter names and values to address types - private static NameToValue[] ntv = { - new NameToValue("TYPE", AddressTypes.None, false), - new NameToValue("DOM", AddressTypes.Domestic, true), - new NameToValue("INTL", AddressTypes.International, true), - new NameToValue("POSTAL", AddressTypes.Postal, true), - new NameToValue("PARCEL", AddressTypes.Parcel, true), - new NameToValue("HOME", AddressTypes.Home, true), - new NameToValue("WORK", AddressTypes.Work, true), - new NameToValue("PREF", AddressTypes.Preferred, true) - }; + private static readonly NameToValue[] ntv = + [ + new("TYPE", AddressTypes.None, false), + new("DOM", AddressTypes.Domestic, true), + new("INTL", AddressTypes.International, true), + new("POSTAL", AddressTypes.Postal, true), + new("PARCEL", AddressTypes.Parcel, true), + new("HOME", AddressTypes.Home, true), + new("WORK", AddressTypes.Work, true), + new("PREF", AddressTypes.Preferred, true) + ]; #endregion #region Properties @@ -88,8 +88,10 @@ public override SpecificationVersions Version if(value == SpecificationVersions.vCard21) this.EncodingMethod = EncodingType.QuotedPrintable; else + { if(this.EncodingMethod == EncodingType.QuotedPrintable) this.EncodingMethod = EncodingType.EightBit; + } } } @@ -123,7 +125,7 @@ public LabelProperty() /// A clone of the object public override object Clone() { - LabelProperty o = new LabelProperty(); + LabelProperty o = new(); o.Clone(this); return o; } @@ -151,9 +153,10 @@ public override void SerializeParameters(StringBuilder sb) // Serialize the address types if necessary if(this.AddressTypes != AddressTypes.None && this.AddressTypes != defaultValue) { - StringBuilder sbTypes = new StringBuilder(50); + StringBuilder sbTypes = new(50); for(int idx = 1; idx < ntv.Length; idx++) + { if((this.AddressTypes & ntv[idx].EnumValue) != 0) { if(sbTypes.Length > 0) @@ -161,6 +164,7 @@ public override void SerializeParameters(StringBuilder sb) sbTypes.Append(ntv[idx].Name); } + } // The format is different for the 3.0 spec if(this.Version == SpecificationVersions.vCard21) @@ -221,8 +225,10 @@ public override void DeserializeParameters(StringCollection parameters) foreach(string s in types) { for(subIdx = 1; subIdx < ntv.Length; subIdx++) + { if(ntv[subIdx].IsMatch(s)) break; + } // Unrecognized ones are ignored if(subIdx < ntv.Length) diff --git a/Source/EWSPDIData/PDIProperties/LabelPropertyCollection.cs b/Source/EWSPDIData/PDIProperties/LabelPropertyCollection.cs index d7168e0..4aab7c4 100644 --- a/Source/EWSPDIData/PDIProperties/LabelPropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/LabelPropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : LabelPropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for LabelProperty objects. It is used with the Personal Data // Interchange (PDI) vCard class. @@ -65,9 +64,9 @@ public LabelPropertyCollection(IList labels) : base(labels) /// There are two overloads for this method public LabelProperty Add(string label) { - LabelProperty l = new LabelProperty { Value = label }; + LabelProperty l = new() { Value = label }; - base.Add(l); + this.Add(l); return l; } @@ -80,9 +79,9 @@ public LabelProperty Add(string label) /// Returns the new property that was created and added to the collection public LabelProperty Add(AddressTypes addressTypes, string label) { - LabelProperty l = new LabelProperty { AddressTypes = addressTypes, Value = label }; + LabelProperty l = new() { AddressTypes = addressTypes, Value = label }; - base.Add(l); + this.Add(l); return l; } @@ -129,10 +128,12 @@ public void SetPreferred(int idx) throw new ArgumentOutOfRangeException(nameof(idx), idx, LR.GetString("ExLabelInvalidIndex")); for(int lblIdx = 0; lblIdx < base.Count; lblIdx++) + { if(lblIdx == idx) this[lblIdx].AddressTypes |= AddressTypes.Preferred; else this[lblIdx].AddressTypes &= ~AddressTypes.Preferred; + } base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } @@ -146,15 +147,19 @@ public void SetPreferred(int idx) /// the one with the Preferred flag set. If a preferred label with one of the given types cannot /// be found, it will return the first label matching one of the given types without the Preferred /// flag set. If no label can be found, it returns null. - public LabelProperty FindFirstByType(AddressTypes addressType) + public LabelProperty? FindFirstByType(AddressTypes addressType) { AddressTypes addrNoPref = addressType & ~AddressTypes.Preferred; bool usePreferred = (addrNoPref != addressType); foreach(LabelProperty label in this) + { if((label.AddressTypes & addrNoPref) != 0 && (!usePreferred || (label.AddressTypes & AddressTypes.Preferred) != 0)) + { return label; + } + } // Try again without the preferred flag? if(usePreferred) diff --git a/Source/EWSPDIData/PDIProperties/LastModifiedProperty.cs b/Source/EWSPDIData/PDIProperties/LastModifiedProperty.cs index 1e14f86..c2e5b8e 100644 --- a/Source/EWSPDIData/PDIProperties/LastModifiedProperty.cs +++ b/Source/EWSPDIData/PDIProperties/LastModifiedProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : LastModifiedProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Last Modified property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -58,7 +57,7 @@ public class LastModifiedProperty : BaseDateTimeProperty /// /// This property does not allow a time zone and is always a UTC date/time value /// - public override string Value + public override string? Value { get { @@ -96,7 +95,7 @@ public LastModifiedProperty() /// A clone of the object public override object Clone() { - LastModifiedProperty o = new LastModifiedProperty(); + LastModifiedProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/LastRevisionProperty.cs b/Source/EWSPDIData/PDIProperties/LastRevisionProperty.cs index 3680c1f..0b9bcc6 100644 --- a/Source/EWSPDIData/PDIProperties/LastRevisionProperty.cs +++ b/Source/EWSPDIData/PDIProperties/LastRevisionProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : LastRevisionProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Last Revision property class used by the Personal Data Interchange (PDI) vCard class // @@ -71,7 +70,7 @@ public LastRevisionProperty() /// A clone of the object public override object Clone() { - LastRevisionProperty o = new LastRevisionProperty(); + LastRevisionProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/LocationProperty.cs b/Source/EWSPDIData/PDIProperties/LocationProperty.cs index 9642b2e..de39b0f 100644 --- a/Source/EWSPDIData/PDIProperties/LocationProperty.cs +++ b/Source/EWSPDIData/PDIProperties/LocationProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : LocationProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contain the Location property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -73,7 +72,7 @@ public LocationProperty() /// A clone of the object public override object Clone() { - LocationProperty o = new LocationProperty(); + LocationProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/LogoProperty.cs b/Source/EWSPDIData/PDIProperties/LogoProperty.cs index 2363d8e..a71e61d 100644 --- a/Source/EWSPDIData/PDIProperties/LogoProperty.cs +++ b/Source/EWSPDIData/PDIProperties/LogoProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : LogoProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Logo property that support binary encoded images. It is used with the Personal Data // Interchange (PDI) vCard class. @@ -64,7 +63,7 @@ public LogoProperty() /// A clone of the object public override object Clone() { - LogoProperty o = new LogoProperty(); + LogoProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/MailerProperty.cs b/Source/EWSPDIData/PDIProperties/MailerProperty.cs index 2fc571e..790d5ca 100644 --- a/Source/EWSPDIData/PDIProperties/MailerProperty.cs +++ b/Source/EWSPDIData/PDIProperties/MailerProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : MailerProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains Mailer property class used by the Personal Data Interchange (PDI) vCard class // @@ -73,7 +72,7 @@ public MailerProperty() /// A clone of the object public override object Clone() { - MailerProperty o = new MailerProperty(); + MailerProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/MemberProperty.cs b/Source/EWSPDIData/PDIProperties/MemberProperty.cs index 203caff..e327bb9 100644 --- a/Source/EWSPDIData/PDIProperties/MemberProperty.cs +++ b/Source/EWSPDIData/PDIProperties/MemberProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : MemberProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/20/2019 -// Note : Copyright 2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2019-2025, Eric Woodruff, All rights reserved // // This file contains the member property class used by the Personal Data Interchange (PDI) vCard class // @@ -67,7 +67,7 @@ public MemberProperty() /// A clone of the object public override object Clone() { - MemberProperty o = new MemberProperty(); + MemberProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/MethodProperty.cs b/Source/EWSPDIData/PDIProperties/MethodProperty.cs index 092b0df..c8ea8f5 100644 --- a/Source/EWSPDIData/PDIProperties/MethodProperty.cs +++ b/Source/EWSPDIData/PDIProperties/MethodProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : MethodProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Method property used by the Personal Data Interchange (PDI) iCalendar classes // @@ -36,7 +35,7 @@ public class MethodProperty : BaseProperty //===================================================================== private CalendarMethod calendarMethod; - private string otherMethod; + private string? otherMethod; #endregion @@ -84,7 +83,7 @@ public CalendarMethod CalendarMethod /// /// Setting this parameter automatically sets the property to /// Other. - public string OtherMethod + public string? OtherMethod { get => otherMethod; set @@ -102,11 +101,11 @@ public string OtherMethod /// This property is overridden to handle converting the text value to a /// value. /// - public override string Value + public override string? Value { get { - string method; + string? method; switch(calendarMethod) { @@ -182,7 +181,7 @@ public override string Value /// This property is overridden to handle converting the text value to a /// value. /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -211,7 +210,7 @@ public MethodProperty() /// A clone of the object public override object Clone() { - MethodProperty o = new MethodProperty(); + MethodProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/MimeNameProperty.cs b/Source/EWSPDIData/PDIProperties/MimeNameProperty.cs index 789ad70..28fbe01 100644 --- a/Source/EWSPDIData/PDIProperties/MimeNameProperty.cs +++ b/Source/EWSPDIData/PDIProperties/MimeNameProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : MimeNameProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains Mime Name property class used by the Personal Data Interchange (PDI) vCard class // @@ -74,7 +73,7 @@ public MimeNameProperty() /// A clone of the object public override object Clone() { - MimeNameProperty o = new MimeNameProperty(); + MimeNameProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/MimeSourceProperty.cs b/Source/EWSPDIData/PDIProperties/MimeSourceProperty.cs index 4270760..aeada6e 100644 --- a/Source/EWSPDIData/PDIProperties/MimeSourceProperty.cs +++ b/Source/EWSPDIData/PDIProperties/MimeSourceProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : MimeSourceProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains Mime Source property class used by the Personal Data Interchange (PDI) vCard class // @@ -58,7 +57,7 @@ public class MimeSourceProperty : BaseProperty /// /// The value is a string defining the context of the property value such as LDAP, HTTP, etc. It /// is only applicable to vCard 3.0 objects. - public string Context { get; set; } + public string? Context { get; set; } #endregion @@ -83,7 +82,7 @@ public MimeSourceProperty() /// A clone of the object public override object Clone() { - MimeSourceProperty o = new MimeSourceProperty(); + MimeSourceProperty o = new(); o.Clone(this); return o; } @@ -126,6 +125,7 @@ public override void DeserializeParameters(StringCollection parameters) return; for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) + { if(String.Compare(parameters[paramIdx], "CONTEXT=", StringComparison.OrdinalIgnoreCase) == 0) { // Remove the parameter name @@ -140,6 +140,7 @@ public override void DeserializeParameters(StringCollection parameters) } break; } + } // Let the base class handle all other parameters base.DeserializeParameters(parameters); diff --git a/Source/EWSPDIData/PDIProperties/NameProperty.cs b/Source/EWSPDIData/PDIProperties/NameProperty.cs index b6da902..0289d1c 100644 --- a/Source/EWSPDIData/PDIProperties/NameProperty.cs +++ b/Source/EWSPDIData/PDIProperties/NameProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : NameProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/14/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Name property class used by the Personal Data Interchange (PDI) vCard class // @@ -34,7 +33,7 @@ public class NameProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reSplit = new Regex(@"(?:^[;])|(?<=(?:[^\\]))[;]"); + private static readonly Regex reSplit = new(@"(?:^[;])|(?<=(?:[^\\]))[;]"); #endregion @@ -60,33 +59,33 @@ public class NameProperty : BaseProperty /// /// This property is used to set or get the family name (last name) /// - public string FamilyName { get; set; } + public string? FamilyName { get; set; } /// /// This property is used to set or get the given name (first name) /// - public string GivenName { get; set; } + public string? GivenName { get; set; } /// /// This property is used to set or get additional names such as one or more middle names /// - public string AdditionalNames { get; set; } + public string? AdditionalNames { get; set; } /// /// This property is used to set or get the name prefix (i.e. Mr., Mrs.) /// - public string NamePrefix { get; set; } + public string? NamePrefix { get; set; } /// /// This property is used to set or get the name suffix (i.e. Jr, Sr) /// - public string NameSuffix { get; set; } + public string? NameSuffix { get; set; } /// /// This property is used to set or get the string to use when sorting names /// /// If set, this value should be given precedence over the property - public string SortAs { get; set; } + public string? SortAs { get; set; } /// /// This read-only property can be used to get the name in a format suitable for sorting by last name @@ -102,19 +101,19 @@ public string SortableName // Only include as much as necessary if(!String.IsNullOrWhiteSpace(this.FamilyName)) - parts[count++] = this.FamilyName; + parts[count++] = this.FamilyName!; if(!String.IsNullOrWhiteSpace(this.GivenName)) - parts[count++] = this.GivenName; + parts[count++] = this.GivenName!; if(!String.IsNullOrWhiteSpace(this.AdditionalNames)) - parts[count++] = this.AdditionalNames; + parts[count++] = this.AdditionalNames!; if(!String.IsNullOrWhiteSpace(this.NameSuffix)) - parts[count++] = this.NameSuffix; + parts[count++] = this.NameSuffix!; if(!String.IsNullOrWhiteSpace(this.NamePrefix)) - parts[count++] = this.NamePrefix; + parts[count++] = this.NamePrefix!; // If empty, return "Unknown" as it is a required property if(count == 0) @@ -136,19 +135,19 @@ public string FormattedName // Only include as much as necessary if(!String.IsNullOrWhiteSpace(this.NamePrefix)) - parts[count++] = this.NamePrefix; + parts[count++] = this.NamePrefix!; if(!String.IsNullOrWhiteSpace(this.GivenName)) - parts[count++] = this.GivenName; + parts[count++] = this.GivenName!; if(!String.IsNullOrWhiteSpace(this.AdditionalNames)) - parts[count++] = this.AdditionalNames; + parts[count++] = this.AdditionalNames!; if(!String.IsNullOrWhiteSpace(this.FamilyName)) - parts[count++] = this.FamilyName; + parts[count++] = this.FamilyName!; if(!String.IsNullOrWhiteSpace(this.NameSuffix)) - parts[count++] = this.NameSuffix; + parts[count++] = this.NameSuffix!; // If empty, return "Unknown" as it is a required property if(count == 0) @@ -166,12 +165,12 @@ public string FormattedName /// value for both the 2.1 and 3.0 specifications. The parts will be escaped as needed. /// This is thrown if an attempt is made to set this property to /// null. - public override string Value + public override string? Value { get { SpecificationVersions v = this.Version; - string[] parts = new string[5]; + string?[] parts = new string[5]; int count = 0; // Only include as much as necessary @@ -271,15 +270,15 @@ public override string Value /// value for both the 2.1 and 3.0 specifications. The parts will be escaped as needed. /// This is thrown if an attempt is made to set this property to /// null. - public override string EncodedValue + public override string? EncodedValue { get { - string nameValue = this.Value; + string? nameValue = this.Value; // Encode using the character set? If so, unescape the backslashes as they get double-encoded. if(this.Version == SpecificationVersions.vCard21) - nameValue = base.Encode(nameValue).Replace(@"\\", @"\"); + nameValue = base.Encode(nameValue)?.Replace(@"\\", @"\"); return nameValue; } @@ -313,7 +312,7 @@ public NameProperty() /// A clone of the object public override object Clone() { - NameProperty o = new NameProperty(); + NameProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/NicknameProperty.cs b/Source/EWSPDIData/PDIProperties/NicknameProperty.cs index 22caa69..31eb4b3 100644 --- a/Source/EWSPDIData/PDIProperties/NicknameProperty.cs +++ b/Source/EWSPDIData/PDIProperties/NicknameProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : NicknameProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Nickname property class used by the Personal Data Interchange (PDI) vCard class // @@ -35,9 +34,9 @@ public class NicknameProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reSplit = new Regex(@"(?:^[,;])|(?<=(?:[^\\]))[,;]"); + private static readonly Regex reSplit = new(@"(?:^[,;])|(?<=(?:[^\\]))[,;]"); - private StringCollection nicknames; + private readonly StringCollection nicknames; #endregion @@ -77,18 +76,15 @@ public string NicknamesString get => String.Join(", ", nicknames); set { - string tempName; - string[] entries; - nicknames.Clear(); if(value != null) { - entries = value.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); + string[] entries = value.Split([',', ';'], StringSplitOptions.RemoveEmptyEntries); foreach(string s in entries) { - tempName = s.Trim(); + string tempName = s.Trim(); if(tempName.Length > 0) nicknames.Add(tempName); @@ -101,7 +97,7 @@ public string NicknamesString /// This property is overridden to handle parsing the nicknames and concatenating them when requested /// /// The nicknames are escaped as needed - public override string Value + public override string? Value { get { @@ -109,7 +105,7 @@ public override string Value if(this.Nicknames.Count == 0) return null; - StringBuilder sb = new StringBuilder(256); + StringBuilder sb = new(256); foreach(string s in this.Nicknames) { @@ -123,19 +119,16 @@ public override string Value } set { - string tempName; - string[] entries; - this.Nicknames.Clear(); if(value != null && value.Length > 0) { // Split on all semi-colons and commas except escaped ones - entries = reSplit.Split(value); + string[] entries = reSplit.Split(value); foreach(string s in entries) { - tempName = EncodingUtils.Unescape(s.Trim()); + string tempName = EncodingUtils.Unescape(s.Trim())!; if(tempName.Length > 0) nicknames.Add(tempName); @@ -148,7 +141,7 @@ public override string Value /// This property is overridden to handle parsing the nicknames and concatenating them when requested /// /// The nicknames are escaped as needed - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -164,7 +157,7 @@ public override string EncodedValue public NicknameProperty() { this.Version = SpecificationVersions.vCard30; - nicknames = new StringCollection(); + nicknames = []; } #endregion @@ -177,7 +170,7 @@ public NicknameProperty() /// A clone of the object public override object Clone() { - NicknameProperty o = new NicknameProperty(); + NicknameProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/NoteProperty.cs b/Source/EWSPDIData/PDIProperties/NoteProperty.cs index 14b32e1..5cc00b4 100644 --- a/Source/EWSPDIData/PDIProperties/NoteProperty.cs +++ b/Source/EWSPDIData/PDIProperties/NoteProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : NoteProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Note property and its collection class. It is used with the Personal Data Interchange // (PDI) vCard class. @@ -89,7 +88,7 @@ public NoteProperty() /// A clone of the object public override object Clone() { - NoteProperty o = new NoteProperty(); + NoteProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/NotePropertyCollection.cs b/Source/EWSPDIData/PDIProperties/NotePropertyCollection.cs index 9ef902d..e3ccad9 100644 --- a/Source/EWSPDIData/PDIProperties/NotePropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/NotePropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : NotePropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for LabelProperty objects. It is used with the Personal Data // Interchange (PDI) vCard class. @@ -63,9 +62,9 @@ public NotePropertyCollection(IList notes) : base(notes) /// Returns the new property that was created and added to the collection public NoteProperty Add(string note) { - NoteProperty n = new NoteProperty { Value = note }; + NoteProperty n = new() { Value = note }; - base.Add(n); + this.Add(n); return n; } diff --git a/Source/EWSPDIData/PDIProperties/OrganizationProperty.cs b/Source/EWSPDIData/PDIProperties/OrganizationProperty.cs index 5e3dc00..675e393 100644 --- a/Source/EWSPDIData/PDIProperties/OrganizationProperty.cs +++ b/Source/EWSPDIData/PDIProperties/OrganizationProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : OrganizationProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/14/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Organization property class used by the Personal Data Interchange (PDI) vCard class // @@ -35,9 +34,9 @@ public class OrganizationProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reSplit = new Regex(@"(?:^[;])|(?<=(?:[^\\]))[;]"); + private static readonly Regex reSplit = new(@"(?:^[;])|(?<=(?:[^\\]))[;]"); - private StringCollection units; + private readonly StringCollection units; #endregion @@ -63,13 +62,13 @@ public class OrganizationProperty : BaseProperty /// /// This property is used to set or get the organization name /// - public string Name { get; set; } + public string? Name { get; set; } /// /// This property is used to set or get the string to use when sorting organizations /// /// If set, this value should be given precedence over the property - public string SortAs { get; set; } + public string? SortAs { get; set; } /// /// This property is used to get the Organization Units string collection @@ -87,18 +86,15 @@ public string UnitsString get => String.Join(", ", units); set { - string tempUnit; - string[] entries; - units.Clear(); if(value != null) { - entries = value.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); + string[] entries = value.Split([',', ';'], StringSplitOptions.RemoveEmptyEntries); foreach(string s in entries) { - tempUnit = s.Trim(); + string tempUnit = s.Trim(); if(tempUnit.Length > 0) units.Add(tempUnit); @@ -112,7 +108,7 @@ public string UnitsString /// requested. /// /// The component parts are escaped as needed - public override string Value + public override string? Value { get { @@ -122,7 +118,7 @@ public override string Value if(String.IsNullOrWhiteSpace(this.Name) && this.Units.Count == 0) return null; - StringBuilder sb = new StringBuilder(256); + StringBuilder sb = new(256); if(v == SpecificationVersions.vCard21) sb.Append(EncodingUtils.RestrictedEscape(this.Name)); @@ -143,22 +139,19 @@ public override string Value } set { - string tempUnit; - string[] parts; - this.Name = null; this.Units.Clear(); if(!String.IsNullOrWhiteSpace(value)) { // Split on all semi-colons except escaped ones - parts = reSplit.Split(value); + string[] parts = reSplit.Split(value); this.Name = EncodingUtils.Unescape(parts[0]); for(int idx = 1; idx < parts.Length; idx++) { - tempUnit = EncodingUtils.Unescape(parts[idx].Trim()); + string tempUnit = EncodingUtils.Unescape(parts[idx].Trim())!; if(tempUnit.Length > 0) this.Units.Add(tempUnit); @@ -172,15 +165,15 @@ public override string Value /// requested. /// /// The component parts are escaped as needed - public override string EncodedValue + public override string? EncodedValue { get { - string orgValue = this.Value; + string? orgValue = this.Value; // Encode using the character set? If so, unescape the backslashes as they get double-encoded. if(orgValue != null && this.Version == SpecificationVersions.vCard21) - orgValue = base.Encode(orgValue).Replace(@"\\", @"\"); + orgValue = base.Encode(orgValue)?.Replace(@"\\", @"\"); return orgValue; } @@ -196,7 +189,7 @@ public override string EncodedValue /// public OrganizationProperty() { - units = new StringCollection(); + units = []; } #endregion @@ -209,7 +202,7 @@ public OrganizationProperty() /// A clone of the object public override object Clone() { - OrganizationProperty o = new OrganizationProperty(); + OrganizationProperty o = new(); o.Clone(this); return o; } @@ -245,6 +238,7 @@ public override void DeserializeParameters(StringCollection parameters) return; for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) + { if(String.Compare(parameters[paramIdx], "SORT-AS=", StringComparison.OrdinalIgnoreCase) == 0) { // Remove the parameter name @@ -259,6 +253,7 @@ public override void DeserializeParameters(StringCollection parameters) } break; } + } // Let the base class handle all other parameters base.DeserializeParameters(parameters); diff --git a/Source/EWSPDIData/PDIProperties/OrganizerProperty.cs b/Source/EWSPDIData/PDIProperties/OrganizerProperty.cs index 04fa689..3bad43e 100644 --- a/Source/EWSPDIData/PDIProperties/OrganizerProperty.cs +++ b/Source/EWSPDIData/PDIProperties/OrganizerProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : OrganizerProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Organizer property. This property only applies to iCalendar 2.0 // @@ -58,21 +57,21 @@ public class OrganizerProperty : BaseProperty /// specified by the property value. /// /// This parameter is only applicable to iCalendar 2.0 objects - public string CommonName { get; set; } + public string? CommonName { get; set; } /// /// This property is used to set or get the directory entry (DIR) parameter associated with the calendar /// user specified by the property value. /// /// This parameter is only applicable to iCalendar 2.0 objects - public string DirectoryEntry { get; set; } + public string? DirectoryEntry { get; set; } /// /// This property is used to set or get the sent-by (SENT-BY) parameter that specifies the calendar user /// that is acting on behalf of the calendar user specified by the property value. /// /// This parameter is only applicable to iCalendar 2.0 objects - public string SentBy { get; set; } + public string? SentBy { get; set; } #endregion @@ -97,7 +96,7 @@ public OrganizerProperty() /// A clone of the object public override object Clone() { - OrganizerProperty o = new OrganizerProperty(); + OrganizerProperty o = new(); o.Clone(this); return o; } @@ -135,7 +134,7 @@ public override void SerializeParameters(StringBuilder sb) sb.Append(ParameterNames.CommonName); sb.Append('='); - if(this.CommonName.IndexOfAny(new char[] { ',', ';', ':' }) != -1) + if(this.CommonName!.IndexOfAny([',', ';', ':']) != -1) { sb.Append('\"'); sb.Append(this.CommonName); @@ -192,6 +191,7 @@ public override void DeserializeParameters(StringCollection parameters) } } else + { if(String.Compare(parameters[paramIdx], "DIR=", StringComparison.OrdinalIgnoreCase) == 0) { parameters.RemoveAt(paramIdx); @@ -203,6 +203,7 @@ public override void DeserializeParameters(StringCollection parameters) } } else + { if(String.Compare(parameters[paramIdx], "SENT-BY=", StringComparison.OrdinalIgnoreCase) == 0) { parameters.RemoveAt(paramIdx); @@ -213,6 +214,8 @@ public override void DeserializeParameters(StringCollection parameters) parameters.RemoveAt(paramIdx); } } + } + } } // Let the base class handle all other parameters diff --git a/Source/EWSPDIData/PDIProperties/PercentCompleteProperty.cs b/Source/EWSPDIData/PDIProperties/PercentCompleteProperty.cs index e7dd8e0..6076a77 100644 --- a/Source/EWSPDIData/PDIProperties/PercentCompleteProperty.cs +++ b/Source/EWSPDIData/PDIProperties/PercentCompleteProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : PercentCompleteProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Percent Complete property class used by the Personal Data Interchange (PDI) vCalendar // and iCalendar classes. @@ -37,7 +36,7 @@ public class PercentCompleteProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reNumber = new Regex(@"^\d*$"); + private static readonly Regex reNumber = new(@"^\d*$"); private int percentage; @@ -84,7 +83,7 @@ public int Percentage /// /// The value should be between 0 and 100. Instead of throwing an exception, the property will /// convert invalid values to zero. - public override string Value + public override string? Value { get { @@ -111,7 +110,7 @@ public override string Value /// /// This property is overridden to handle converting the text value to a numeric value /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -139,7 +138,7 @@ public PercentCompleteProperty() /// A clone of the object public override object Clone() { - PercentCompleteProperty o = new PercentCompleteProperty(); + PercentCompleteProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/PhotoProperty.cs b/Source/EWSPDIData/PDIProperties/PhotoProperty.cs index f48037c..27749ad 100644 --- a/Source/EWSPDIData/PDIProperties/PhotoProperty.cs +++ b/Source/EWSPDIData/PDIProperties/PhotoProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : PhotoProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/18/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Photo property that support binary encoded images. It is used with the Personal Data // Interchange (PDI) vCard class. @@ -38,26 +38,27 @@ public class PhotoProperty : BaseProperty //===================================================================== // This private array is used to translate parameter names and values to image types - private static readonly NameToValue[] ntv = { - new NameToValue("TYPE", 0, false), - new NameToValue("GIF", 1, true), - new NameToValue("CGM", 2, true), - new NameToValue("WMF", 3, true), - new NameToValue("BMP", 4, true), - new NameToValue("MET", 5, true), - new NameToValue("PMB", 6, true), - new NameToValue("DIB", 7, true), - new NameToValue("PICT", 8, true), - new NameToValue("TIFF", 9, true), - new NameToValue("PS", 10, true), - new NameToValue("PDF", 11, true), - new NameToValue("JPEG", 12, true), - new NameToValue("MPEG", 13, true), - new NameToValue("MPEG2", 14, true), - new NameToValue("AVI", 15, true), - new NameToValue("QTIME", 16, true), - new NameToValue("PNG", 17, true) - }; + private static readonly NameToValue[] ntv = + [ + new("TYPE", 0, false), + new("GIF", 1, true), + new("CGM", 2, true), + new("WMF", 3, true), + new("BMP", 4, true), + new("MET", 5, true), + new("PMB", 6, true), + new("DIB", 7, true), + new("PICT", 8, true), + new("TIFF", 9, true), + new("PS", 10, true), + new("PDF", 11, true), + new("JPEG", 12, true), + new("MPEG", 13, true), + new("MPEG2", 14, true), + new("AVI", 15, true), + new("QTIME", 16, true), + new("PNG", 17, true) + ]; #endregion #region Properties @@ -85,12 +86,12 @@ public class PhotoProperty : BaseProperty /// The value is a string defining the type of image that the property value represents such as /// GIF, JPEG, TIFF, AVI, etc. /// - public string ImageType { get; set; } + public string? ImageType { get; set; } /// /// This is overridden to handle the URI prefix on vCard 4.0 values /// - public override string EncodedValue + public override string? EncodedValue { get { @@ -100,7 +101,7 @@ public override string EncodedValue string value = "data:"; if(!String.IsNullOrWhiteSpace(this.ImageType)) - value += "image/" + this.ImageType.ToLowerInvariant() + ";base64,"; + value += "image/" + this.ImageType!.ToLowerInvariant() + ";base64,"; return value + this.Encode(base.Value); } @@ -157,7 +158,7 @@ public PhotoProperty() /// A clone of the object public override object Clone() { - PhotoProperty o = new PhotoProperty(); + PhotoProperty o = new(); o.Clone(this); return o; } @@ -210,8 +211,10 @@ public override void DeserializeParameters(StringCollection parameters) for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) { for(idx = 0; idx < ntv.Length; idx++) + { if(ntv[idx].IsMatch(parameters[paramIdx])) break; + } if(idx == ntv.Length) { diff --git a/Source/EWSPDIData/PDIProperties/PriorityProperty.cs b/Source/EWSPDIData/PDIProperties/PriorityProperty.cs index 7757ce5..5880d57 100644 --- a/Source/EWSPDIData/PDIProperties/PriorityProperty.cs +++ b/Source/EWSPDIData/PDIProperties/PriorityProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : PriorityProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Priority property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -81,7 +80,7 @@ public int PriorityValue /// /// The value should be between 0 and 9. Instead of throwing an exception, the property will /// convert invalid values to the undefined priority (0). - public override string Value + public override string? Value { get { @@ -103,7 +102,7 @@ public override string Value /// /// This property is overridden to handle converting the text value to a numeric value /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -130,7 +129,7 @@ public PriorityProperty() /// A clone of the object public override object Clone() { - PriorityProperty o = new PriorityProperty(); + PriorityProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/ProductIdProperty.cs b/Source/EWSPDIData/PDIProperties/ProductIdProperty.cs index 9aa0fed..8a3c779 100644 --- a/Source/EWSPDIData/PDIProperties/ProductIdProperty.cs +++ b/Source/EWSPDIData/PDIProperties/ProductIdProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ProductIdProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Product ID property class used by the Personal Data Interchange (PDI) classes such as // vCalendar, iCalendar, and vCard. @@ -37,7 +36,7 @@ public class ProductIdProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reSplit = new Regex("//"); + private static readonly Regex reSplit = new("//"); #endregion @@ -69,24 +68,24 @@ public class ProductIdProperty : BaseProperty /// /// This is used to set or get the product owner name /// - public string OwnerName { get; set; } + public string? OwnerName { get; set; } /// /// This is used to set or get the keyword description /// - public string KeywordDescription { get; set; } + public string? KeywordDescription { get; set; } /// /// This is used to set or get the language /// - public string ProductLanguage { get; set; } + public string? ProductLanguage { get; set; } /// /// This property is overridden to handle parsing the product ID components and concatenating them when /// requested. /// /// If some but not all parts are specified, default values are used for the missing parts - public override string Value + public override string? Value { get { @@ -109,8 +108,8 @@ public override string Value this.IsRegistered = false; } - return String.Join("//", new[] { (this.IsRegistered ? "+" : "-"), this.OwnerName, - this.KeywordDescription, this.ProductLanguage }); + return String.Join("//", [ (this.IsRegistered ? "+" : "-"), this.OwnerName, + this.KeywordDescription, this.ProductLanguage ]); } set { @@ -141,7 +140,7 @@ public override string Value /// requested. /// /// If some but not all parts are specified, default values are used for the missing parts - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -168,7 +167,7 @@ public ProductIdProperty() /// A clone of the object public override object Clone() { - ProductIdProperty o = new ProductIdProperty(); + ProductIdProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/PublicKeyProperty.cs b/Source/EWSPDIData/PDIProperties/PublicKeyProperty.cs index bd658ce..f7f4fbc 100644 --- a/Source/EWSPDIData/PDIProperties/PublicKeyProperty.cs +++ b/Source/EWSPDIData/PDIProperties/PublicKeyProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : PublicKeyProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Public Key property that support binary encoded public key values. It is used with // the Personal Data Interchange (PDI) vCard class. @@ -39,11 +38,12 @@ public class PublicKeyProperty : BaseProperty //===================================================================== // This private array is used to translate parameter names and values to public key types - private static NameToValue[] ntv = { - new NameToValue("TYPE", 0, false), - new NameToValue("X509", 1, true), - new NameToValue("PGP", 2, true) - }; + private static readonly NameToValue[] ntv = + [ + new("TYPE", 0, false), + new("X509", 1, true), + new("PGP", 2, true) + ]; #endregion #region Properties @@ -70,7 +70,7 @@ public class PublicKeyProperty : BaseProperty /// /// The value is a string defining the type of key that the property value represents such as /// X509, PGP, etc. - public string KeyType { get; set; } + public string? KeyType { get; set; } #endregion @@ -95,7 +95,7 @@ public PublicKeyProperty() /// A clone of the object public override object Clone() { - PublicKeyProperty o = new PublicKeyProperty(); + PublicKeyProperty o = new(); o.Clone(this); return o; } @@ -148,8 +148,10 @@ public override void DeserializeParameters(StringCollection parameters) for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) { for(idx = 0; idx < ntv.Length; idx++) + { if(ntv[idx].IsMatch(parameters[paramIdx])) break; + } if(idx == ntv.Length) { diff --git a/Source/EWSPDIData/PDIProperties/RDateProperty.cs b/Source/EWSPDIData/PDIProperties/RDateProperty.cs index 79cda3e..30b7ef2 100644 --- a/Source/EWSPDIData/PDIProperties/RDateProperty.cs +++ b/Source/EWSPDIData/PDIProperties/RDateProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RDateProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a class for the RDATE property used by the Personal Data Interchange (PDI) classes such as // vCalendar and iCalendar. @@ -40,8 +39,8 @@ public class RDateProperty : BaseProperty #region Private data members //===================================================================== - private Period period; - private string timeZoneId; + private Period? period; + private string? timeZoneId; #endregion @@ -88,7 +87,7 @@ public class RDateProperty : BaseProperty /// value, the time part of the property value is considered to be expressed in local time for the given /// time zone rather than universal time. The ID should match a time zone ID on a VTIMEZONE component in /// the owning calendar. If set, the property is ignored. - public string TimeZoneId + public string? TimeZoneId { get => timeZoneId; set @@ -233,7 +232,7 @@ public Period PeriodValue /// /// This property is overridden to handle parsing the date/time or period to/from its string form /// - public override string Value + public override string? Value { get { @@ -299,7 +298,7 @@ public override string Value /// /// This property is overridden to handle parsing the date/time to/from its string form /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -328,7 +327,7 @@ public RDateProperty() /// A clone of the object public override object Clone() { - RDateProperty o = new RDateProperty(); + RDateProperty o = new(); o.Clone(this); return o; } @@ -359,7 +358,7 @@ public override void SerializeParameters(StringBuilder sb) sb.Append(ParameterNames.TimeZoneId); sb.Append('='); - if(timeZoneId.IndexOfAny(new char[] { ',', ';', ':' }) != -1) + if(timeZoneId.IndexOfAny([',', ';', ':']) != -1) { sb.Append('\"'); sb.Append(timeZoneId); @@ -380,6 +379,7 @@ public override void DeserializeParameters(StringCollection parameters) return; for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) + { if(String.Compare(parameters[paramIdx], "TZID=", StringComparison.OrdinalIgnoreCase) == 0) { // Remove the parameter name @@ -394,6 +394,7 @@ public override void DeserializeParameters(StringCollection parameters) } break; } + } // Let the base class handle all other parameters base.DeserializeParameters(parameters); diff --git a/Source/EWSPDIData/PDIProperties/RDatePropertyCollection.cs b/Source/EWSPDIData/PDIProperties/RDatePropertyCollection.cs index 4c85a5d..9618c84 100644 --- a/Source/EWSPDIData/PDIProperties/RDatePropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/RDatePropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RDatePropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for RDateProperty objects. It is used with the Personal Data // Interchange (PDI) vCalendar and iCalendar classes. @@ -65,9 +64,9 @@ public RDatePropertyCollection(IList recurDates) : base(recurDate /// There are two overloads for this method public RDateProperty Add(DateTime dt) { - RDateProperty rdt = new RDateProperty { DateTimeValue = dt }; + RDateProperty rdt = new() { DateTimeValue = dt }; - base.Add(rdt); + this.Add(rdt); return rdt; } @@ -79,9 +78,9 @@ public RDateProperty Add(DateTime dt) /// Returns the new property that was created and added to the collection public RDateProperty Add(Period p) { - RDateProperty rdt = new RDateProperty { PeriodValue = p }; + RDateProperty rdt = new() { PeriodValue = p }; - base.Add(rdt); + this.Add(rdt); return rdt; } diff --git a/Source/EWSPDIData/PDIProperties/RRuleProperty.cs b/Source/EWSPDIData/PDIProperties/RRuleProperty.cs index bc8d537..bfd576f 100644 --- a/Source/EWSPDIData/PDIProperties/RRuleProperty.cs +++ b/Source/EWSPDIData/PDIProperties/RRuleProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RRuleProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Recurrence Rule property. It is used with the Personal Data Interchange (PDI) // vCalendar and iCalendar classes. @@ -32,7 +31,7 @@ public class RRuleProperty : BaseProperty #region Private data members //===================================================================== - private Recurrence recur; + private Recurrence? recur; #endregion @@ -64,8 +63,7 @@ public Recurrence Recurrence { get { - if(recur == null) - recur = new Recurrence(); + recur ??= new Recurrence(); return recur; } @@ -74,7 +72,7 @@ public Recurrence Recurrence /// /// This is overridden to handle parsing of the recurrence value to/from its string form /// - public override string Value + public override string? Value { get { @@ -93,7 +91,7 @@ public override string Value /// /// This is overridden to handle parsing of the recurrence value to/from its string form /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -122,7 +120,7 @@ public RRuleProperty() /// A clone of the object public override object Clone() { - RRuleProperty o = new RRuleProperty(); + RRuleProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/RecurrenceCountProperty.cs b/Source/EWSPDIData/PDIProperties/RecurrenceCountProperty.cs index 0ef59bc..f9ba451 100644 --- a/Source/EWSPDIData/PDIProperties/RecurrenceCountProperty.cs +++ b/Source/EWSPDIData/PDIProperties/RecurrenceCountProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RecurrenceCountProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Recurrence Count property class used by the Personal Data Interchange (PDI) vCalendar // and iCalendar classes. @@ -36,7 +35,7 @@ public class RecurrenceCountProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reNumber = new Regex(@"^\d*$"); + private static readonly Regex reNumber = new(@"^\d*$"); private int count; @@ -82,7 +81,7 @@ public int Count /// /// Instead of throwing an exception, the property will convert non-numeric values to the default /// count (0). - public override string Value + public override string? Value { get { @@ -109,7 +108,7 @@ public override string Value /// /// This property is overridden to handle converting the text value to a numeric value /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -137,7 +136,7 @@ public RecurrenceCountProperty() /// A clone of the object public override object Clone() { - RecurrenceCountProperty o = new RecurrenceCountProperty(); + RecurrenceCountProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/RecurrenceIdProperty.cs b/Source/EWSPDIData/PDIProperties/RecurrenceIdProperty.cs index 43e2d56..ce24a5f 100644 --- a/Source/EWSPDIData/PDIProperties/RecurrenceIdProperty.cs +++ b/Source/EWSPDIData/PDIProperties/RecurrenceIdProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RecurrenceIdProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Recurrence ID property class used by the Personal Data Interchange (PDI) iCalendar // class. @@ -41,7 +40,7 @@ public class RecurrenceIdProperty : BaseDateTimeProperty #region Private data members //===================================================================== - private string range; + private string? range; #endregion @@ -67,7 +66,7 @@ public class RecurrenceIdProperty : BaseDateTimeProperty /// /// This property is used to get or set the range (RANGE) parameter /// - public string Range + public string? Range { get => range; set @@ -101,7 +100,7 @@ public RecurrenceIdProperty() /// A clone of the object public override object Clone() { - RecurrenceIdProperty o = new RecurrenceIdProperty(); + RecurrenceIdProperty o = new(); o.Clone(this); return o; } @@ -144,6 +143,7 @@ public override void DeserializeParameters(StringCollection parameters) return; for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) + { if(String.Compare(parameters[paramIdx], "RANGE=", StringComparison.OrdinalIgnoreCase) == 0) { // Remove the parameter name @@ -158,6 +158,7 @@ public override void DeserializeParameters(StringCollection parameters) } break; } + } // Let the base class handle all other parameters base.DeserializeParameters(parameters); diff --git a/Source/EWSPDIData/PDIProperties/RelatedProperty.cs b/Source/EWSPDIData/PDIProperties/RelatedProperty.cs index 930fd94..2801f0f 100644 --- a/Source/EWSPDIData/PDIProperties/RelatedProperty.cs +++ b/Source/EWSPDIData/PDIProperties/RelatedProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : RelatedProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/20/2019 -// Note : Copyright 2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2019-2025, Eric Woodruff, All rights reserved // // This file contains the Related property. It is used with the vCard 4.0 Personal Data Interchange (PDI) // classes. @@ -38,33 +38,34 @@ public class RelatedProperty : BaseProperty #region Private data members //===================================================================== - private static readonly Regex reSplit = new Regex(@"(?:^[,])|(?<=(?:[^\\]))[,]"); + private static readonly Regex reSplit = new(@"(?:^[,])|(?<=(?:[^\\]))[,]"); // This private array is used to translate parameter names and values to phone types - private static readonly NameToValue[] ntv = { - new NameToValue("PREF", RelatedTypes.None, false), - new NameToValue("TYPE", RelatedTypes.None, false), - new NameToValue("ACQUIANTANCE", RelatedTypes.Acquaintance, true), - new NameToValue("AGENT", RelatedTypes.Agent, true), - new NameToValue("CHILD", RelatedTypes.Child, true), - new NameToValue("CO-RESIDENT", RelatedTypes.CoResident, true), - new NameToValue("CO-WORKER", RelatedTypes.CoWorker, true), - new NameToValue("COLLEAGUE", RelatedTypes.Colleague, true), - new NameToValue("CONTACT", RelatedTypes.Contact, true), - new NameToValue("CRUSH", RelatedTypes.Crush, true), - new NameToValue("DATE", RelatedTypes.Date, true), - new NameToValue("EMERGENCY", RelatedTypes.Emergency, true), - new NameToValue("FRIEND", RelatedTypes.Friend, true), - new NameToValue("KIN", RelatedTypes.Kin, true), - new NameToValue("ME", RelatedTypes.Me, true), - new NameToValue("MET", RelatedTypes.Met, true), - new NameToValue("MUSE", RelatedTypes.Muse, true), - new NameToValue("NEIGHBOR", RelatedTypes.Neighbor, true), - new NameToValue("PARENT", RelatedTypes.Parent, true), - new NameToValue("SIBLING", RelatedTypes.Sibling, true), - new NameToValue("SPOUSE", RelatedTypes.Spouse, true), - new NameToValue("SWEETHEART", RelatedTypes.Sweetheart, true), - }; + private static readonly NameToValue[] ntv = + [ + new("PREF", RelatedTypes.None, false), + new("TYPE", RelatedTypes.None, false), + new("ACQUIANTANCE", RelatedTypes.Acquaintance, true), + new("AGENT", RelatedTypes.Agent, true), + new("CHILD", RelatedTypes.Child, true), + new("CO-RESIDENT", RelatedTypes.CoResident, true), + new("CO-WORKER", RelatedTypes.CoWorker, true), + new("COLLEAGUE", RelatedTypes.Colleague, true), + new("CONTACT", RelatedTypes.Contact, true), + new("CRUSH", RelatedTypes.Crush, true), + new("DATE", RelatedTypes.Date, true), + new("EMERGENCY", RelatedTypes.Emergency, true), + new("FRIEND", RelatedTypes.Friend, true), + new("KIN", RelatedTypes.Kin, true), + new("ME", RelatedTypes.Me, true), + new("MET", RelatedTypes.Met, true), + new("MUSE", RelatedTypes.Muse, true), + new("NEIGHBOR", RelatedTypes.Neighbor, true), + new("PARENT", RelatedTypes.Parent, true), + new("SIBLING", RelatedTypes.Sibling, true), + new("SPOUSE", RelatedTypes.Spouse, true), + new("SWEETHEART", RelatedTypes.Sweetheart, true), + ]; private short preferredOrder; @@ -136,7 +137,7 @@ public RelatedProperty() /// A clone of the object public override object Clone() { - RelatedProperty o = new RelatedProperty(); + RelatedProperty o = new(); o.Clone(this); return o; } @@ -169,9 +170,10 @@ public override void SerializeParameters(StringBuilder sb) // Serialize the related types if necessary if(rt != RelatedTypes.None) { - StringBuilder sbTypes = new StringBuilder(50); + StringBuilder sbTypes = new(50); for(int idx = 1; idx < ntv.Length; idx++) + { if((rt & ntv[idx].EnumValue) != 0) { if(sbTypes.Length > 0) @@ -179,6 +181,7 @@ public override void SerializeParameters(StringBuilder sb) sbTypes.Append(ntv[idx].Name.ToLowerInvariant()); } + } sbTypes.Insert(0, "="); sbTypes.Insert(0, ParameterNames.Type); @@ -205,8 +208,10 @@ public override void DeserializeParameters(StringCollection parameters) for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) { for(idx = 0; idx < ntv.Length; idx++) + { if(ntv[idx].IsMatch(parameters[paramIdx])) break; + } if(idx == ntv.Length) { @@ -244,8 +249,10 @@ public override void DeserializeParameters(StringCollection parameters) foreach(string s in types) { for(subIdx = 1; subIdx < ntv.Length; subIdx++) + { if(ntv[subIdx].IsMatch(s)) break; + } // Unrecognized ones are ignored if(subIdx < ntv.Length) diff --git a/Source/EWSPDIData/PDIProperties/RelatedPropertyCollection.cs b/Source/EWSPDIData/PDIProperties/RelatedPropertyCollection.cs index bbf90e7..78cf53f 100644 --- a/Source/EWSPDIData/PDIProperties/RelatedPropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/RelatedPropertyCollection.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : RelatedPropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/20/2019 -// Note : Copyright 2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2019-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for RelatedProperty objects. It is used with the Personal Data // Interchange (PDI) vCard class. @@ -45,8 +45,8 @@ public RelatedPropertyCollection() /// /// Construct the collection using a list of objects /// - /// The of related-to items to add - public RelatedPropertyCollection(IList Relateds) : base(Relateds) + /// The of related-to items to add + public RelatedPropertyCollection(IList relateds) : base(relateds) { } #endregion @@ -62,7 +62,7 @@ public RelatedPropertyCollection(IList Relateds) : base(Related /// Returns the new property that was created and added to the collection public RelatedProperty Add(RelatedTypes relatedTypes, string relation) { - RelatedProperty rt = new RelatedProperty { RelatedTypes = relatedTypes, Value = relation }; + RelatedProperty rt = new() { RelatedTypes = relatedTypes, Value = relation }; base.Add(rt); @@ -87,11 +87,13 @@ public void PropagateVersion(SpecificationVersions version) /// The phone type to match /// The entry with a related type matching one of those specified or null if not found /// Multiple related types can be specified. If no entry can be found, it returns null. - public RelatedProperty FindFirstByType(RelatedTypes relatedTypes) + public RelatedProperty? FindFirstByType(RelatedTypes relatedTypes) { foreach(var r in this) + { if((r.RelatedTypes & relatedTypes) != 0) return r; + } return null; } diff --git a/Source/EWSPDIData/PDIProperties/RelatedToProperty.cs b/Source/EWSPDIData/PDIProperties/RelatedToProperty.cs index a36c987..429f762 100644 --- a/Source/EWSPDIData/PDIProperties/RelatedToProperty.cs +++ b/Source/EWSPDIData/PDIProperties/RelatedToProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RelatedToProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Related To property. It is used with the vCalendar and iCalendar Personal Data // Interchange (PDI) classes. @@ -37,7 +36,7 @@ public class RelatedToProperty : BaseProperty //===================================================================== private RelationshipType relType; - private string otherType; + private string? otherType; #endregion @@ -88,7 +87,7 @@ public RelationshipType RelationshipType /// /// This parameter is only applicable to iCalendar 2.0 objects. Setting this parameter /// automatically sets the property to Other. - public string OtherRelationship + public string? OtherRelationship { get => otherType; set @@ -126,7 +125,7 @@ public RelatedToProperty() /// A clone of the object public override object Clone() { - RelatedToProperty o = new RelatedToProperty(); + RelatedToProperty o = new(); o.Clone(this); return o; } @@ -200,6 +199,7 @@ public override void DeserializeParameters(StringCollection parameters) return; for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) + { if(String.Compare(parameters[paramIdx], "RELTYPE=", StringComparison.OrdinalIgnoreCase) == 0) { // Remove the parameter name @@ -233,6 +233,7 @@ public override void DeserializeParameters(StringCollection parameters) } break; } + } // Let the base class handle all other parameters base.DeserializeParameters(parameters); diff --git a/Source/EWSPDIData/PDIProperties/RelatedToPropertyCollection.cs b/Source/EWSPDIData/PDIProperties/RelatedToPropertyCollection.cs index 263eacb..35a250b 100644 --- a/Source/EWSPDIData/PDIProperties/RelatedToPropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/RelatedToPropertyCollection.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : RelatedToPropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/20/2019 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for RelatedToProperty objects. It is used with the Personal Data // Interchange (PDI) vCalendar and iCalendar class. @@ -63,7 +63,7 @@ public RelatedToPropertyCollection(IList relatedTos) : base(r /// Returns the new property that was created and added to the collection public RelatedToProperty Add(RelationshipType rType, string relation) { - RelatedToProperty rt = new RelatedToProperty { RelationshipType = rType, Value = relation }; + RelatedToProperty rt = new() { RelationshipType = rType, Value = relation }; base.Add(rt); diff --git a/Source/EWSPDIData/PDIProperties/RepeatProperty.cs b/Source/EWSPDIData/PDIProperties/RepeatProperty.cs index 5c7b06f..79ab0a6 100644 --- a/Source/EWSPDIData/PDIProperties/RepeatProperty.cs +++ b/Source/EWSPDIData/PDIProperties/RepeatProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RepeatProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Repeat property used by the Personal Data Interchange (PDI) vCalendar and iCalendar // VAlarm class. @@ -36,7 +35,7 @@ public class RepeatProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reNumber = new Regex(@"^\d*$"); + private static readonly Regex reNumber = new(@"^\d*$"); private int repeatCount; @@ -83,7 +82,7 @@ public int RepeatCount /// /// Instead of throwing an exception, the property will convert non-numeric values to the default /// repeat count (0). - public override string Value + public override string? Value { get { @@ -110,7 +109,7 @@ public override string Value /// /// This property is overridden to handle converting the text value to a numeric value /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -137,7 +136,7 @@ public RepeatProperty() /// A clone of the object public override object Clone() { - RepeatProperty o = new RepeatProperty(); + RepeatProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/RequestStatusProperty.cs b/Source/EWSPDIData/PDIProperties/RequestStatusProperty.cs index e128de4..90868b3 100644 --- a/Source/EWSPDIData/PDIProperties/RequestStatusProperty.cs +++ b/Source/EWSPDIData/PDIProperties/RequestStatusProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RequestStatusProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Request Status property. It is used with the iCalendar Personal Data Interchange // (PDI) classes. @@ -52,36 +51,36 @@ public class RequestStatusProperty : BaseProperty /// /// This is used to get or set the status code value /// - public string StatusCode { get; set; } + public string? StatusCode { get; set; } /// /// This is used to get or set the status message /// - public string StatusMessage { get; set; } + public string? StatusMessage { get; set; } /// /// This is used to get or set the extended data value /// - public string ExtendedData { get; set; } + public string? ExtendedData { get; set; } /// /// This property is overridden to handle parsing the request status components and concatenating them /// when requested. /// - public override string Value + public override string? Value { get { - string statValue = null; + string? statValue = null; // Return nothing if undefined if(!String.IsNullOrWhiteSpace(this.StatusCode) || !String.IsNullOrWhiteSpace(this.StatusMessage) || !String.IsNullOrWhiteSpace(this.ExtendedData)) { - statValue = String.Join(";", new[] { this.StatusCode, this.StatusMessage }); + statValue = String.Join(";", [this.StatusCode, this.StatusMessage]); if(!String.IsNullOrWhiteSpace(this.ExtendedData)) - statValue = String.Join(";", new[] { statValue, this.ExtendedData }); + statValue = String.Join(";", [statValue, this.ExtendedData]); } return statValue; @@ -110,7 +109,7 @@ public override string Value /// This property is overridden to handle parsing the request status components and concatenating them /// when requested. /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -138,7 +137,7 @@ public RequestStatusProperty() /// A clone of the object public override object Clone() { - RequestStatusProperty o = new RequestStatusProperty(); + RequestStatusProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/RequestStatusPropertyCollection.cs b/Source/EWSPDIData/PDIProperties/RequestStatusPropertyCollection.cs index a780271..8c169b9 100644 --- a/Source/EWSPDIData/PDIProperties/RequestStatusPropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/RequestStatusPropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RequestStatusPropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for RequestStatusProperty objects. It is used by the Personal Data // Interchange (PDI) iCalendar class. @@ -66,14 +65,14 @@ public RequestStatusPropertyCollection(IList stats) : bas /// Returns the new property that was created and added to the collection public RequestStatusProperty Add(string code, string message, string data) { - RequestStatusProperty rs = new RequestStatusProperty + RequestStatusProperty rs = new() { StatusCode = code, StatusMessage = message, ExtendedData = data }; - base.Add(rs); + this.Add(rs); return rs; } diff --git a/Source/EWSPDIData/PDIProperties/ResourcesProperty.cs b/Source/EWSPDIData/PDIProperties/ResourcesProperty.cs index 791acf4..c80e955 100644 --- a/Source/EWSPDIData/PDIProperties/ResourcesProperty.cs +++ b/Source/EWSPDIData/PDIProperties/ResourcesProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : ResourcesProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Resources property class used by the Personal Data Interchange (PDI) classes such as // vCalendar and iCalendar. @@ -36,9 +35,9 @@ public class ResourcesProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reSplit = new Regex(@"(?:^[,;])|(?<=(?:[^\\]))[,;]"); + private static readonly Regex reSplit = new(@"(?:^[,;])|(?<=(?:[^\\]))[,;]"); - private StringCollection resources; + private readonly StringCollection resources; #endregion @@ -78,18 +77,15 @@ public string ResourcesString get => String.Join(", ", resources); set { - string tempRes; - string[] entries; - resources.Clear(); if(value != null) { - entries = value.Split(',', ';'); + string[] entries = value.Split(',', ';'); foreach(string s in entries) { - tempRes = s.Trim(); + string tempRes = s.Trim(); if(tempRes.Length > 0) resources.Add(tempRes); @@ -102,7 +98,7 @@ public string ResourcesString /// This property is overridden to handle parsing the resources and concatenating them when requested /// /// The resources are escaped as needed - public override string Value + public override string? Value { get { @@ -110,7 +106,7 @@ public override string Value if(this.Resources.Count == 0) return null; - StringBuilder sb = new StringBuilder(256); + StringBuilder sb = new(256); foreach(string s in this.Resources) { @@ -129,19 +125,16 @@ public override string Value } set { - string tempRes; - string[] entries; - this.Resources.Clear(); if(value != null && value.Length > 0) { // Split on all semi-colons and commas except escaped ones - entries = reSplit.Split(value); + string[] entries = reSplit.Split(value); foreach(string s in entries) { - tempRes = EncodingUtils.Unescape(s.Trim()); + string tempRes = EncodingUtils.Unescape(s.Trim())!; if(tempRes.Length > 0) resources.Add(tempRes); @@ -154,7 +147,7 @@ public override string Value /// This property is overridden to handle parsing the resources and concatenating them when requested /// /// The resources are escaped as needed - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -171,7 +164,7 @@ public override string EncodedValue public ResourcesProperty() { this.Version = SpecificationVersions.iCalendar20; - resources = new StringCollection(); + resources = []; } #endregion @@ -184,7 +177,7 @@ public ResourcesProperty() /// A clone of the object public override object Clone() { - ResourcesProperty o = new ResourcesProperty(); + ResourcesProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/RoleProperty.cs b/Source/EWSPDIData/PDIProperties/RoleProperty.cs index 4cb4e59..fc123a1 100644 --- a/Source/EWSPDIData/PDIProperties/RoleProperty.cs +++ b/Source/EWSPDIData/PDIProperties/RoleProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : RoleProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Role property class used by the Personal Data Interchange (PDI) vCard class // @@ -69,7 +68,7 @@ public RoleProperty() /// A clone of the object public override object Clone() { - RoleProperty o = new RoleProperty(); + RoleProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/SequenceProperty.cs b/Source/EWSPDIData/PDIProperties/SequenceProperty.cs index 10c5e77..aef7fef 100644 --- a/Source/EWSPDIData/PDIProperties/SequenceProperty.cs +++ b/Source/EWSPDIData/PDIProperties/SequenceProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : SequenceProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Sequence property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -36,7 +35,7 @@ public class SequenceProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reNumber = new Regex(@"^\d*$"); + private static readonly Regex reNumber = new(@"^\d*$"); private int sequenceNumber; @@ -83,7 +82,7 @@ public int SequenceNumber /// /// Instead of throwing an exception, the property will convert non-numeric values to the default /// sequence number (0). - public override string Value + public override string? Value { get { @@ -110,7 +109,7 @@ public override string Value /// /// This property is overridden to handle converting the text value to a numeric value /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -137,7 +136,7 @@ public SequenceProperty() /// A clone of the object public override object Clone() { - SequenceProperty o = new SequenceProperty(); + SequenceProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/SortStringProperty.cs b/Source/EWSPDIData/PDIProperties/SortStringProperty.cs index ac361eb..be9052a 100644 --- a/Source/EWSPDIData/PDIProperties/SortStringProperty.cs +++ b/Source/EWSPDIData/PDIProperties/SortStringProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : SortStringProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Sort String property class used by the Personal Data Interchange (PDI) vCard class // @@ -72,7 +71,7 @@ public SortStringProperty() /// A clone of the object public override object Clone() { - SortStringProperty o = new SortStringProperty(); + SortStringProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/SoundProperty.cs b/Source/EWSPDIData/PDIProperties/SoundProperty.cs index decd23e..7f7616a 100644 --- a/Source/EWSPDIData/PDIProperties/SoundProperty.cs +++ b/Source/EWSPDIData/PDIProperties/SoundProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : SoundProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/18/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Sound property that support binary encoded sounds. It is used with the Personal Data // Interchange (PDI) vCard class. @@ -38,13 +38,14 @@ public class SoundProperty : BaseProperty //===================================================================== // This private array is used to translate parameter names and values to sound types - private static readonly NameToValue[] ntv = { - new NameToValue("TYPE", 0, false), - new NameToValue("WAVE", 1, true), - new NameToValue("PCM", 2, true), - new NameToValue("AIF", 3, true), - new NameToValue("BASIC", 4, true) - }; + private static readonly NameToValue[] ntv = + [ + new("TYPE", 0, false), + new("WAVE", 1, true), + new("PCM", 2, true), + new("AIF", 3, true), + new("BASIC", 4, true) + ]; #endregion #region Properties @@ -69,7 +70,7 @@ public class SoundProperty : BaseProperty /// /// This is overridden to handle the URI prefix on vCard 4.0 values /// - public override string EncodedValue + public override string? EncodedValue { get { @@ -79,7 +80,7 @@ public override string EncodedValue string value = "data:"; if(!String.IsNullOrWhiteSpace(this.SoundType)) - value += "audio/" + this.SoundType.ToLowerInvariant() + ";base64,"; + value += "audio/" + this.SoundType!.ToLowerInvariant() + ";base64,"; return value + this.Encode(base.Value); } @@ -119,7 +120,7 @@ public override string EncodedValue /// /// The value is a string defining the type of sound that the property value represents such as /// basic, WAV, etc. - public string SoundType { get; set; } + public string? SoundType { get; set; } #endregion @@ -145,7 +146,7 @@ public SoundProperty() /// A clone of the object public override object Clone() { - SoundProperty o = new SoundProperty(); + SoundProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/SpecificationVersions.cs b/Source/EWSPDIData/PDIProperties/SpecificationVersions.cs index b0be0e5..fa45d67 100644 --- a/Source/EWSPDIData/PDIProperties/SpecificationVersions.cs +++ b/Source/EWSPDIData/PDIProperties/SpecificationVersions.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : SpecificationVersions.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This enumerated type defines the various specification versions that can be supported by the objects // @@ -27,9 +26,9 @@ namespace EWSoftware.PDI.Properties /// /// This enumerated type defines the various specification versions that can be supported by the objects /// - /// - /// - /// + /// + /// + /// [Flags, Serializable] public enum SpecificationVersions { diff --git a/Source/EWSPDIData/PDIProperties/StartDateProperty.cs b/Source/EWSPDIData/PDIProperties/StartDateProperty.cs index 7836b7b..7e97478 100644 --- a/Source/EWSPDIData/PDIProperties/StartDateProperty.cs +++ b/Source/EWSPDIData/PDIProperties/StartDateProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : StartDateProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Start Date property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -74,7 +73,7 @@ public StartDateProperty() /// A clone of the object public override object Clone() { - StartDateProperty o = new StartDateProperty(); + StartDateProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/StatusProperty.cs b/Source/EWSPDIData/PDIProperties/StatusProperty.cs index d3c10f8..529ad7d 100644 --- a/Source/EWSPDIData/PDIProperties/StatusProperty.cs +++ b/Source/EWSPDIData/PDIProperties/StatusProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : StatusProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Status property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -35,21 +34,22 @@ public class StatusProperty : BaseAltRepProperty //===================================================================== // This private array is used to translate status value names to enumerated status values - private static NameToValue[] ntv = { - new NameToValue("ACCEPTED", StatusValue.Accepted, true), - new NameToValue("NEEDS-ACTION", StatusValue.NeedsAction, true), - new NameToValue("NEEDS ACTION", StatusValue.NeedsAction, true), - new NameToValue("SENT", StatusValue.Sent, true), - new NameToValue("TENTATIVE", StatusValue.Tentative, true), - new NameToValue("CONFIRMED", StatusValue.Confirmed, true), - new NameToValue("DECLINED", StatusValue.Declined, true), - new NameToValue("COMPLETED", StatusValue.Completed, true), - new NameToValue("DELEGATED", StatusValue.Delegated, true), - new NameToValue("CANCELLED", StatusValue.Cancelled, true), - new NameToValue("IN-PROCESS", StatusValue.InProcess, true), - new NameToValue("DRAFT", StatusValue.Draft, true), - new NameToValue("FINAL", StatusValue.Final, true) - }; + private static readonly NameToValue[] ntv = + [ + new("ACCEPTED", StatusValue.Accepted, true), + new("NEEDS-ACTION", StatusValue.NeedsAction, true), + new("NEEDS ACTION", StatusValue.NeedsAction, true), + new("SENT", StatusValue.Sent, true), + new("TENTATIVE", StatusValue.Tentative, true), + new("CONFIRMED", StatusValue.Confirmed, true), + new("DECLINED", StatusValue.Declined, true), + new("COMPLETED", StatusValue.Completed, true), + new("DELEGATED", StatusValue.Delegated, true), + new("CANCELLED", StatusValue.Cancelled, true), + new("IN-PROCESS", StatusValue.InProcess, true), + new("DRAFT", StatusValue.Draft, true), + new("FINAL", StatusValue.Final, true) + ]; #endregion #region Properties @@ -80,7 +80,7 @@ public class StatusProperty : BaseAltRepProperty /// /// This property is overridden to handle converting the text value to an enumerated status value /// - public override string Value + public override string? Value { get { @@ -89,8 +89,10 @@ public override string Value return null; for(int idx = 0; idx < ntv.Length; idx++) + { if(this.StatusValue == ntv[idx].EnumValue) return ntv[idx].Name; + } return null; } @@ -99,19 +101,23 @@ public override string Value this.StatusValue = StatusValue.None; if(value != null && value.Length != 0) + { for(int idx = 0; idx < ntv.Length; idx++) + { if(ntv[idx].IsMatch(value)) { this.StatusValue = ntv[idx].EnumValue; break; } + } + } } } /// /// This property is overridden to handle converting the text value to an enumerated status value /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -140,7 +146,7 @@ public StatusProperty() /// A clone of the object public override object Clone() { - StatusProperty o = new StatusProperty(); + StatusProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/SummaryProperty.cs b/Source/EWSPDIData/PDIProperties/SummaryProperty.cs index 93f3e54..9d46dec 100644 --- a/Source/EWSPDIData/PDIProperties/SummaryProperty.cs +++ b/Source/EWSPDIData/PDIProperties/SummaryProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : SummaryProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/03/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Summary property class used by the Personal Data Interchange (PDI) vCalendar and // iCalendar classes. @@ -75,7 +74,7 @@ public SummaryProperty() /// A clone of the object public override object Clone() { - SummaryProperty o = new SummaryProperty(); + SummaryProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/TelephoneProperty.cs b/Source/EWSPDIData/PDIProperties/TelephoneProperty.cs index c766778..d4f7857 100644 --- a/Source/EWSPDIData/PDIProperties/TelephoneProperty.cs +++ b/Source/EWSPDIData/PDIProperties/TelephoneProperty.cs @@ -2,8 +2,8 @@ // System : Personal Data Interchange Classes // File : TelephoneProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/16/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Telephone property class. It is used with the Personal Data Interchange (PDI) vCard // class. @@ -42,31 +42,32 @@ public class TelephoneProperty : BaseProperty #region Private data members //===================================================================== - private static readonly Regex reSplit = new Regex(@"(?:^[,])|(?<=(?:[^\\]))[,]"); + private static readonly Regex reSplit = new(@"(?:^[,])|(?<=(?:[^\\]))[,]"); // This private array is used to translate parameter names and values to phone types - private static readonly NameToValue[] ntv = { - new NameToValue("TYPE", PhoneTypes.None, false), - new NameToValue("PREF", PhoneTypes.Preferred, true), - new NameToValue("WORK", PhoneTypes.Work, true), - new NameToValue("HOME", PhoneTypes.Home, true), - new NameToValue("VOICE", PhoneTypes.Voice, true), - new NameToValue("FAX", PhoneTypes.Fax, true), - new NameToValue("MSG", PhoneTypes.Message, true), - new NameToValue("CELL", PhoneTypes.Cell, true), - new NameToValue("PAGER", PhoneTypes.Pager, true), - new NameToValue("BBS", PhoneTypes.BBS, true), - new NameToValue("MODEM", PhoneTypes.Modem, true), - new NameToValue("CAR", PhoneTypes.Car, true), - new NameToValue("ISDN", PhoneTypes.ISDN, true), - new NameToValue("VIDEO", PhoneTypes.Video, true), - new NameToValue("PCS", PhoneTypes.PCS, true), - new NameToValue("TEXT", PhoneTypes.Text, true), - new NameToValue("TEXTPHONE", PhoneTypes.TextPhone, true), + private static readonly NameToValue[] ntv = + [ + new("TYPE", PhoneTypes.None, false), + new("PREF", PhoneTypes.Preferred, true), + new("WORK", PhoneTypes.Work, true), + new("HOME", PhoneTypes.Home, true), + new("VOICE", PhoneTypes.Voice, true), + new("FAX", PhoneTypes.Fax, true), + new("MSG", PhoneTypes.Message, true), + new("CELL", PhoneTypes.Cell, true), + new("PAGER", PhoneTypes.Pager, true), + new("BBS", PhoneTypes.BBS, true), + new("MODEM", PhoneTypes.Modem, true), + new("CAR", PhoneTypes.Car, true), + new("ISDN", PhoneTypes.ISDN, true), + new("VIDEO", PhoneTypes.Video, true), + new("PCS", PhoneTypes.PCS, true), + new("TEXT", PhoneTypes.Text, true), + new("TEXTPHONE", PhoneTypes.TextPhone, true), // This is a non-standard one that pops up every now and then. When it does, treat it like CELL. new NameToValue("MOBILE", PhoneTypes.Cell, true) - }; + ]; private short preferredOrder; @@ -118,12 +119,12 @@ public short PreferredOrder /// /// This is used to get or set the URI prefix if the value location is set to URI /// - public string UriPrefix { get; set; } + public string? UriPrefix { get; set; } /// /// This is overridden to handle the URI prefix on the value if the value location is set to URI /// - public override string EncodedValue + public override string? EncodedValue { get { @@ -135,7 +136,7 @@ public override string EncodedValue set { if(this.ValueLocation == ValLocValue.Uri && !String.IsNullOrWhiteSpace(value) && - value.IndexOf(':') != -1) + value!.IndexOf(':') != -1) { int pos = value.IndexOf(':'); @@ -171,7 +172,7 @@ public TelephoneProperty() /// A clone of the object public override object Clone() { - TelephoneProperty o = new TelephoneProperty(); + TelephoneProperty o = new(); o.Clone(this); return o; } @@ -224,10 +225,11 @@ public override void SerializeParameters(StringBuilder sb) sb.AppendFormat(";PREF={0}", this.PreferredOrder); } - StringBuilder sbTypes = new StringBuilder(50); + StringBuilder sbTypes = new(50); // This ignores the last entry (MOBILE) as it's a duplicate of CELL for(int idx = 1; idx < ntv.Length - 1; idx++) + { if((pt & ntv[idx].EnumValue) != 0) { if(sbTypes.Length > 0) @@ -235,6 +237,7 @@ public override void SerializeParameters(StringBuilder sb) sbTypes.Append(ntv[idx].Name); } + } // The format is different for the 3.0 spec and later if(this.Version == SpecificationVersions.vCard21) @@ -267,8 +270,10 @@ public override void DeserializeParameters(StringCollection parameters) for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) { for(idx = 0; idx < ntv.Length; idx++) + { if(ntv[idx].IsMatch(parameters[paramIdx])) break; + } if(idx == ntv.Length) { @@ -295,8 +300,10 @@ public override void DeserializeParameters(StringCollection parameters) foreach(string s in types) { for(subIdx = 1; subIdx < ntv.Length; subIdx++) + { if(ntv[subIdx].IsMatch(s)) break; + } // Unrecognized ones are ignored if(subIdx < ntv.Length) diff --git a/Source/EWSPDIData/PDIProperties/TelephonePropertyCollection.cs b/Source/EWSPDIData/PDIProperties/TelephonePropertyCollection.cs index 3258857..e0f7284 100644 --- a/Source/EWSPDIData/PDIProperties/TelephonePropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/TelephonePropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TelephonePropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for TelephoneProperty objects. It is used with the Personal Data // Interchange (PDI) vCard class. @@ -64,9 +63,9 @@ public TelephonePropertyCollection(IList phones) : base(phone /// Returns the new property that was created and added to the collection public TelephoneProperty Add(string phone) { - TelephoneProperty t = new TelephoneProperty { Value = phone }; + TelephoneProperty t = new() { Value = phone }; - base.Add(t); + this.Add(t); return t; } @@ -79,9 +78,9 @@ public TelephoneProperty Add(string phone) /// Returns the new property that was created and added to the collection public TelephoneProperty Add(PhoneTypes phoneTypes, string phone) { - TelephoneProperty t = new TelephoneProperty { PhoneTypes = phoneTypes, Value = phone }; + TelephoneProperty t = new() { PhoneTypes = phoneTypes, Value = phone }; - base.Add(t); + this.Add(t); return t; } @@ -129,10 +128,12 @@ public void SetPreferred(int idx) throw new ArgumentOutOfRangeException(nameof(idx), idx, LR.GetString("ExPhoneInvalidIndex")); for(int phoneIdx = 0; phoneIdx < base.Count; phoneIdx++) + { if(phoneIdx == idx) this[phoneIdx].PhoneTypes |= PhoneTypes.Preferred; else this[phoneIdx].PhoneTypes &= ~PhoneTypes.Preferred; + } base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } @@ -146,15 +147,19 @@ public void SetPreferred(int idx) /// the one with the Preferred flag set. If a preferred phone number with one of the given types /// cannot be found, it will return the first phone number matching one of the given types without the /// Preferred flag set. If no phone number can be found, it returns null. - public TelephoneProperty FindFirstByType(PhoneTypes phoneType) + public TelephoneProperty? FindFirstByType(PhoneTypes phoneType) { PhoneTypes phoneNoPref = phoneType & ~PhoneTypes.Preferred; bool usePreferred = (phoneNoPref != phoneType); foreach(TelephoneProperty phone in this) + { if((phone.PhoneTypes & phoneNoPref) != 0 && (!usePreferred || (phone.PhoneTypes & PhoneTypes.Preferred) != 0)) + { return phone; + } + } // Try again without the preferred flag? if(usePreferred) diff --git a/Source/EWSPDIData/PDIProperties/TimeStampProperty.cs b/Source/EWSPDIData/PDIProperties/TimeStampProperty.cs index f6ddbd1..f8d61fe 100644 --- a/Source/EWSPDIData/PDIProperties/TimeStampProperty.cs +++ b/Source/EWSPDIData/PDIProperties/TimeStampProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TimeStampProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the time stamp property class used by the Personal Data Interchange (PDI) iCalendar class // @@ -28,7 +27,7 @@ namespace EWSoftware.PDI.Properties /// This class is used to represent the Time Stamp (DTSTAMP) property of an iCalendar object /// /// This property class parses the property to allow access - /// to its content as an actual object. The property value is a character + /// to its content as an actual object. The property value is a character /// string conforming to the basic format of ISO 8601. The value is in universal time. /// /// This property represents the date and time that the object was converted to vCalendar or iCalendar @@ -60,7 +59,7 @@ public class TimeStampProperty : BaseDateTimeProperty /// /// This property does not allow a time zone and is always a UTC date/time value /// - public override string Value + public override string? Value { get { @@ -97,7 +96,7 @@ public TimeStampProperty() /// A clone of the object public override object Clone() { - TimeStampProperty o = new TimeStampProperty(); + TimeStampProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/TimeTransparencyProperty.cs b/Source/EWSPDIData/PDIProperties/TimeTransparencyProperty.cs index 9eda3e0..a553f40 100644 --- a/Source/EWSPDIData/PDIProperties/TimeTransparencyProperty.cs +++ b/Source/EWSPDIData/PDIProperties/TimeTransparencyProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TimeTransparencyProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Time Transparency property class used by the Personal Data Interchange (PDI) vCalendar // and iCalendar classes. @@ -63,7 +62,7 @@ public class TimeTransparencyProperty : BaseProperty /// /// Instead of throwing an exception, the property will convert unrecognized non-numeric values /// to false. - public override string Value + public override string? Value { get { @@ -79,7 +78,7 @@ public override string Value if(!String.IsNullOrWhiteSpace(value)) { // vCalendar 1.0 uses numeric values. iCalendar 2.0 uses OPAQUE or TRANSPARENT. - this.IsTransparent = ((Char.IsDigit(value[0]) && value[0] != '0') || + this.IsTransparent = ((Char.IsDigit(value![0]) && value[0] != '0') || String.Compare(value.Trim(), "TRANSPARENT", StringComparison.OrdinalIgnoreCase) == 0); } else @@ -90,7 +89,7 @@ public override string Value /// /// This property is overridden to handle converting the text value to a Boolean value /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -119,7 +118,7 @@ public TimeTransparencyProperty() /// A clone of the object public override object Clone() { - TimeTransparencyProperty o = new TimeTransparencyProperty(); + TimeTransparencyProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/TimeZoneIdChangedEventArgs.cs b/Source/EWSPDIData/PDIProperties/TimeZoneIdChangedEventArgs.cs index 072aac3..ff82bdc 100644 --- a/Source/EWSPDIData/PDIProperties/TimeZoneIdChangedEventArgs.cs +++ b/Source/EWSPDIData/PDIProperties/TimeZoneIdChangedEventArgs.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TimeZoneIdChangedEventArgs.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 12/19/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This is a custom EventArgs class for the TimeZoneIdChanged event // @@ -31,19 +30,19 @@ public class TimeZoneIdChangedEventArgs : EventArgs /// /// This property returns the old time zone ID /// - public string OldId { get; private set; } + public string? OldId { get; private set; } /// /// This property returns the new ID /// - public string NewId { get; private set; } + public string? NewId { get; private set; } /// /// Constructor /// /// The old time zone ID /// The new time zone ID - public TimeZoneIdChangedEventArgs(string oldTimeZoneId, string newTimeZoneId) + public TimeZoneIdChangedEventArgs(string? oldTimeZoneId, string? newTimeZoneId) { this.OldId = oldTimeZoneId; this.NewId = newTimeZoneId; diff --git a/Source/EWSPDIData/PDIProperties/TimeZoneIdProperty.cs b/Source/EWSPDIData/PDIProperties/TimeZoneIdProperty.cs index cfad9d8..5c8705d 100644 --- a/Source/EWSPDIData/PDIProperties/TimeZoneIdProperty.cs +++ b/Source/EWSPDIData/PDIProperties/TimeZoneIdProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TimeZoneIdProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Time Zone ID property classes used by the Personal Data Interchange (PDI) iCalendar // classes. @@ -58,7 +57,7 @@ public class TimeZoneIdProperty : BaseProperty /// This is overridden to raise the event when the ID changes /// /// This is thrown if the value is set to null or an empty string - public override string Value + public override string? Value { get => base.Value; set @@ -66,7 +65,7 @@ public override string Value if(String.IsNullOrWhiteSpace(value)) throw new ArgumentException(LR.GetString("ExTZIDCannotBeNull")); - string oldId = base.Value; + string? oldId = base.Value; // If changed, set it and raise the TimeZoneIdChanged event except on first use (old ID = null) if(oldId != value) @@ -83,7 +82,7 @@ public override string Value /// This is overridden to raise the event when the ID changes /// /// This is thrown if the value is set to null - public override string EncodedValue + public override string? EncodedValue { get => base.EncodedValue; set @@ -95,7 +94,7 @@ public override string EncodedValue // The decoded values are sent as the event arguments, not the encoded values. if(base.EncodedValue != value) { - string oldId = base.Value; + string? oldId = base.Value; base.EncodedValue = value; @@ -112,7 +111,7 @@ public override string EncodedValue /// /// This event is raised when the property is changed /// - public event EventHandler TimeZoneIdChanged; + public event EventHandler? TimeZoneIdChanged; /// /// This raises the event @@ -145,7 +144,7 @@ public TimeZoneIdProperty() /// A clone of the object public override object Clone() { - TimeZoneIdProperty o = new TimeZoneIdProperty(); + TimeZoneIdProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/TimeZoneNameProperty.cs b/Source/EWSPDIData/PDIProperties/TimeZoneNameProperty.cs index 659ef00..a8c26b8 100644 --- a/Source/EWSPDIData/PDIProperties/TimeZoneNameProperty.cs +++ b/Source/EWSPDIData/PDIProperties/TimeZoneNameProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TimeZoneNameProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Time Zone Name property classes used by the Personal Data Interchange (PDI) iCalendar // classes. @@ -36,7 +35,7 @@ public class TimeZoneNameProperty : BaseProperty #region Private data members //===================================================================== - private static Regex reSplit = new Regex(@"\s+"); + private static readonly Regex reSplit = new(@"\s+"); #endregion @@ -71,6 +70,9 @@ public string AbbreviatedTimeZoneName { get { + if(String.IsNullOrWhiteSpace(this.Value)) + return String.Empty; + string[] parts = reSplit.Split(this.Value); int count = 0; @@ -80,11 +82,13 @@ public string AbbreviatedTimeZoneName char[] letters = new char[parts.Length]; for(int idx = 0; idx < parts.Length; idx++) + { if(Char.IsLetter(parts[idx][0])) { letters[idx] = parts[idx][0]; count++; } + } return new String(letters, 0, count); } @@ -112,7 +116,7 @@ public TimeZoneNameProperty() /// A clone of the object public override object Clone() { - TimeZoneNameProperty o = new TimeZoneNameProperty(); + TimeZoneNameProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/TimeZoneNamePropertyCollection.cs b/Source/EWSPDIData/PDIProperties/TimeZoneNamePropertyCollection.cs index e61c3ff..87462bc 100644 --- a/Source/EWSPDIData/PDIProperties/TimeZoneNamePropertyCollection.cs +++ b/Source/EWSPDIData/PDIProperties/TimeZoneNamePropertyCollection.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TimeZoneNamePropertyCollection.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains a collection class for TimeZoneNameProperty objects. It is used by the Personal Data // Interchange (PDI) iCalendar class. @@ -65,9 +64,9 @@ public TimeZoneNamePropertyCollection(IList timeZoneNames) /// Returns the new property that was created and added to the collection public TimeZoneNameProperty Add(string tzId) { - TimeZoneNameProperty tzn = new TimeZoneNameProperty { Value = tzId }; + TimeZoneNameProperty tzn = new() { Value = tzId }; - base.Add(tzn); + this.Add(tzn); return tzn; } @@ -80,19 +79,18 @@ public TimeZoneNameProperty Add(string tzId) /// language ID is returned. If an exact match is not found, an attempt is made to locate a match using /// only the two letter ISO language name. If that fails, an attempt is made to find an entry using the /// current culture. If that fails, it returns the first entry in the list or null if there are none. - public TimeZoneNameProperty this[string languageId] + public TimeZoneNameProperty? this[string? languageId] { get { if(languageId == null || languageId.Length == 0) languageId = "??"; - string isoName = languageId.Split('-')[0]; - string currentName = CultureInfo.CurrentCulture.Name; - string currentISOName = CultureInfo.CurrentCulture.TwoLetterISOLanguageName; + string isoName = languageId.Split('-')[0], currentName = CultureInfo.CurrentCulture.Name, + currentISOName = CultureInfo.CurrentCulture.TwoLetterISOLanguageName; int idx, cultureIdx = -1; - TimeZoneNameProperty tzn = null; + TimeZoneNameProperty? tzn = null; string propLang; @@ -114,9 +112,12 @@ public TimeZoneNameProperty this[string languageId] // if all else fails. if(String.Compare(propLang, currentName, StringComparison.InvariantCultureIgnoreCase) == 0) cultureIdx = idx; - else // Only use ISO match if there's no full match + else + { + // Only use ISO match if there's no full match if(cultureIdx == -1 && String.Compare(propLang, currentISOName, StringComparison.InvariantCultureIgnoreCase) == 0) cultureIdx = idx; + } } // Found a match by the passed ID? @@ -128,7 +129,7 @@ public TimeZoneNameProperty this[string languageId] return base[cultureIdx]; // Otherwise, give up and return the first entry in the list or null if there are no entries - if(base.Count != 0) + if(this.Count != 0) return base[0]; return null; diff --git a/Source/EWSPDIData/PDIProperties/TimeZoneOffsetProperty.cs b/Source/EWSPDIData/PDIProperties/TimeZoneOffsetProperty.cs index 2e3da0f..e237520 100644 --- a/Source/EWSPDIData/PDIProperties/TimeZoneOffsetProperty.cs +++ b/Source/EWSPDIData/PDIProperties/TimeZoneOffsetProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TimeZoneOffsetProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Time Zone Offset property classes used by the Personal Data Interchange (PDI) iCalendar // classes. @@ -68,7 +67,7 @@ public class TimeZoneOffsetProperty : BaseProperty /// This property is overridden to handle parsing the time span /// to/from its string form. /// - public override string Value + public override string? Value { get { @@ -103,7 +102,7 @@ public override string Value /// /// This property is overridden to handle parsing the time span to/from its string form /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -134,7 +133,7 @@ public TimeZoneOffsetProperty(bool isOffsetFrom) /// A clone of the object public override object Clone() { - TimeZoneOffsetProperty o = new TimeZoneOffsetProperty(isOffsetFrom); + TimeZoneOffsetProperty o = new(isOffsetFrom); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/TimeZoneProperty.cs b/Source/EWSPDIData/PDIProperties/TimeZoneProperty.cs index bbf67be..657a9bc 100644 --- a/Source/EWSPDIData/PDIProperties/TimeZoneProperty.cs +++ b/Source/EWSPDIData/PDIProperties/TimeZoneProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TimeZoneProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains Time Zone property class used by the Personal Data Interchange (PDI) classes such as // vCalendar and vCard. @@ -98,7 +97,7 @@ public TimeSpan TimeSpanValue /// /// The value assigned can be a time zone value alone or a time zone value with descriptive text /// (VALUE=TEXT). - public override string Value + public override string? Value { get { @@ -112,7 +111,7 @@ public override string Value { // If not a UTC offset, don't set the time span if(this.ValueLocation == ValLocValue.UtcOffset && !String.IsNullOrWhiteSpace(value)) - timeSpan = DateUtils.FromISO8601TimeZone(value); + timeSpan = DateUtils.FromISO8601TimeZone(value!); else timeSpan = TimeSpan.MinValue; @@ -124,7 +123,7 @@ public override string Value /// /// This property is overridden to handle parsing the time zone to/from its string form /// - public override string EncodedValue + public override string? EncodedValue { get { @@ -138,7 +137,7 @@ public override string EncodedValue { // If not a UTC offset, don't set the time span if(this.ValueLocation == ValLocValue.UtcOffset && !String.IsNullOrWhiteSpace(value)) - timeSpan = DateUtils.FromISO8601TimeZone(value); + timeSpan = DateUtils.FromISO8601TimeZone(value!); else timeSpan = TimeSpan.MinValue; @@ -168,7 +167,7 @@ public TimeZoneProperty() /// A clone of the object public override object Clone() { - TimeZoneProperty o = new TimeZoneProperty(); + TimeZoneProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/TimeZoneUrlProperty.cs b/Source/EWSPDIData/PDIProperties/TimeZoneUrlProperty.cs index 7f6212f..b97cd39 100644 --- a/Source/EWSPDIData/PDIProperties/TimeZoneUrlProperty.cs +++ b/Source/EWSPDIData/PDIProperties/TimeZoneUrlProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TimeZoneUrlProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Time Zone URL property class used by the Personal Data Interchange (PDI) iCalendar // class. @@ -72,7 +71,7 @@ public TimeZoneUrlProperty() /// A clone of the object public override object Clone() { - TimeZoneUrlProperty o = new TimeZoneUrlProperty(); + TimeZoneUrlProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/TitleProperty.cs b/Source/EWSPDIData/PDIProperties/TitleProperty.cs index 4bc2ec5..170bfbf 100644 --- a/Source/EWSPDIData/PDIProperties/TitleProperty.cs +++ b/Source/EWSPDIData/PDIProperties/TitleProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : TitleProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Title property class used by the Personal Data Interchange (PDI) vCard class // @@ -69,7 +68,7 @@ public TitleProperty() /// A clone of the object public override object Clone() { - TitleProperty o = new TitleProperty(); + TitleProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/PDIProperties/TriggerProperty.cs b/Source/EWSPDIData/PDIProperties/TriggerProperty.cs index f182a52..ac23671 100644 --- a/Source/EWSPDIData/PDIProperties/TriggerProperty.cs +++ b/Source/EWSPDIData/PDIProperties/TriggerProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : AlarmProperties.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/24/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Trigger property used by the Personal Data Interchange (PDI) vCalendar and iCalendar // VAlarm class. @@ -26,10 +25,10 @@ namespace EWSoftware.PDI.Properties { /// /// This class is used to represent the trigger (TRIGGER) property of an iCalendar - /// object. + /// object. /// /// This property class parses the property to allow access to its - /// content as an actual object or object. The property + /// content as an actual object or object. The property /// value is a character string conforming to ISO 8601. public class TriggerProperty : BaseDateTimeProperty { @@ -68,7 +67,7 @@ public class TriggerProperty : BaseDateTimeProperty /// /// This property is used to set or get the duration to use for the trigger. If set, the - /// and properties will be + /// and properties will be /// ignored. /// public Duration DurationValue @@ -84,7 +83,7 @@ public Duration DurationValue /// /// This is overridden to set or get the date/time to use for the trigger expressed in the /// time rather than local time on the current system. If - /// set, the will be ignored. + /// set, the will be ignored. /// public override DateTime TimeZoneDateTime { @@ -98,7 +97,7 @@ public override DateTime TimeZoneDateTime /// /// This is overridden to set or get the date/time to use for the trigger expressed in local time. If - /// set, the will be ignored. + /// set, the will be ignored. /// public override DateTime DateTimeValue { @@ -113,14 +112,14 @@ public override DateTime DateTimeValue /// /// This property is overridden to handle converting the text value to a duration or date/time value /// - public override string Value + public override string? Value { get { // If it's not a date/time, it's a duration. If it has no length, it isn't saved. if(this.ValueLocation != ValLocValue.DateTime) { - if(this.DurationValue == PDI.Duration.Zero) + if(this.DurationValue == Duration.Zero) return null; return this.DurationValue.ToString(); @@ -150,7 +149,7 @@ public override string Value /// /// This property is overridden to handle converting the text value to a numeric value /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => this.Value = value; @@ -179,7 +178,7 @@ public TriggerProperty() /// A clone of the object public override object Clone() { - TriggerProperty o = new TriggerProperty(); + TriggerProperty o = new(); o.Clone(this); return o; } @@ -221,6 +220,7 @@ public override void DeserializeParameters(StringCollection parameters) return; for(int paramIdx = 0; paramIdx < parameters.Count; paramIdx++) + { if(String.Compare(parameters[paramIdx], "RELATED=", StringComparison.OrdinalIgnoreCase) == 0) { // Remove the parameter name @@ -236,6 +236,7 @@ public override void DeserializeParameters(StringCollection parameters) } break; } + } // Let the base class handle all other parameters base.DeserializeParameters(parameters); diff --git a/Source/EWSPDIData/PDIProperties/UniqueIdProperty.cs b/Source/EWSPDIData/PDIProperties/UniqueIdProperty.cs index 1b5a7ca..32597d2 100644 --- a/Source/EWSPDIData/PDIProperties/UniqueIdProperty.cs +++ b/Source/EWSPDIData/PDIProperties/UniqueIdProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : UniqueIdProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the Unique ID property class used by the Personal Data Interchange (PDI) classes such as // vCalendar, iCalendar, and vCard. @@ -67,12 +66,12 @@ public override string Tag /// /// This is overridden to create a unique ID if one does not already exist /// - public override string Value + public override string? Value { get { if(String.IsNullOrWhiteSpace(base.Value)) - base.Value = System.Guid.NewGuid().ToString().ToUpperInvariant(); + base.Value = Guid.NewGuid().ToString().ToUpperInvariant(); return base.Value; } @@ -82,7 +81,7 @@ public override string Value /// /// This is overridden to create a unique ID if one does not already exist /// - public override string EncodedValue + public override string? EncodedValue { get => this.Value; set => base.Value = value; @@ -111,7 +110,7 @@ public UniqueIdProperty() /// calendar. You must manually assign a new unique ID after cloning if necessary. public override object Clone() { - UniqueIdProperty o = new UniqueIdProperty(); + UniqueIdProperty o = new(); o.Clone(this); return o; } @@ -139,13 +138,13 @@ public override void DeserializeParameters(StringCollection parameters) /// /// If true, a new unique ID is assigned regardless of whether one already exists. /// If false and the object already has a unique ID, it keeps the old one. - /// It returns the new unique ID + /// It returns the new or existing unique ID public string AssignNewId(bool forceNew) { if(!String.IsNullOrWhiteSpace(base.Value) && forceNew) base.Value = null; - return this.Value; + return this.Value!; } #endregion } diff --git a/Source/EWSPDIData/PDIProperties/UrlProperty.cs b/Source/EWSPDIData/PDIProperties/UrlProperty.cs index 0f34478..a6d3987 100644 --- a/Source/EWSPDIData/PDIProperties/UrlProperty.cs +++ b/Source/EWSPDIData/PDIProperties/UrlProperty.cs @@ -2,9 +2,8 @@ // System : Personal Data Interchange Classes // File : UrlProperty.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 01/03/2019 -// Note : Copyright 2004-2019, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/04/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains the URL property class used by the Personal Data Interchange (PDI) classes such as // vCalendar, iCalendar, and vCard. @@ -75,7 +74,7 @@ public UrlProperty() /// A clone of the object public override object Clone() { - UrlProperty o = new UrlProperty(); + UrlProperty o = new(); o.Clone(this); return o; } diff --git a/Source/EWSPDIData/ReadMe.txt b/Source/EWSPDIData/ReadMe.md similarity index 87% rename from Source/EWSPDIData/ReadMe.txt rename to Source/EWSPDIData/ReadMe.md index c47de07..a9ec377 100644 --- a/Source/EWSPDIData/ReadMe.txt +++ b/Source/EWSPDIData/ReadMe.md @@ -1,5 +1,4 @@ -EWSoftware.PDI.Data Library ---------------------------- +# EWSoftware.PDI.Data Library This library contains classes used to create and consume vCard, vCalendar, and iCalendar files used to exchange contact and appointment information between applications such as Microsoft Outlook. diff --git a/Source/EWSPDIWeb/EWSoftware.PDI.Web.Controls.csproj b/Source/EWSPDIWeb/EWSoftware.PDI.Web.Controls.csproj index d9de735..8a88c19 100644 --- a/Source/EWSPDIWeb/EWSoftware.PDI.Web.Controls.csproj +++ b/Source/EWSPDIWeb/EWSoftware.PDI.Web.Controls.csproj @@ -7,10 +7,10 @@ Eric Woodruff EWSoftware Personal Data Interchange Library EWSoftware PDI Web Controls Library - Copyright (c) 2003-2023, Eric Woodruff, All Rights Reserved + Copyright (c) 2003-2025, Eric Woodruff, All Rights Reserved en - 2023.1.2.0 - 23.1.2.0 + 2025.1.9.0 + 25.1.9.0 This library contains some web controls that can be used to edit recurrence settings. See the project website for the code, a help file, and demos. Eric Woodruff https://raw.githubusercontent.com/EWSoftware/PDI/master/EWSPDI.png @@ -21,45 +21,32 @@ https://github.com/EWSoftware/PDI MS-PL Targets .NET Framework 4.0 and later (Windows platform only) - true + ReadMe.md False False False False + true ..\EWSPDI.snk true AllEnabledByDefault pdbonly true + latest + enable - - - - - - - - - - - - - - + - + - - true - \ - + @@ -73,7 +60,7 @@ - + diff --git a/Source/EWSPDIWeb/GlobalSuppressions.cs b/Source/EWSPDIWeb/GlobalSuppressions.cs index d881d4203e3a58e5dff842939680e6c8687c923b..ed0b7cb88c52a7afebd91dcc2c9e3936cff32e03 100644 GIT binary patch delta 384 zcmdm_^+{vHIcCmMhGK?HhCGJ!$q$(wS*;m(8Mr1-6qKE;#>_YQkD%J-D3$<57-zB^ z+Zq^qvmLt{vV`2`ZyZ5zfz5lk;t-rZo*pC)pBEB`M}cv2j-V6B)Xjec8xS%dgq;{C zAK;gO+9y;W%uvEm$&ka4%Amxc!=L~pJsDgWTp0`)3>l1pq!oi7Ln1>iP`;R<0LV%P zvJ@Cn81lg)3P3OB15Ho>sz?OV$qX4lb{bGD2dE~Mp$Nz;28tIklmg{SfMgL+6k?MX zkXNh+6wCx_$OKA*49Em(%>!z(1!5%z8-@U&@;snX;IL${o2 delta 172 zcmeyQu}N#gIp)dBSS2RkVYXq^oBW^Od~+U403(7sS%*VzvH)8js>tRKY#d06HtTQ{ vAagHp#vyYT@F_4(ZsN&7n6Y^QpA_R{8$JURp(LoL&Hwo)BI`dQ=)?#B!jU}g diff --git a/Source/EWSPDIWeb/LocalizedResources.cs b/Source/EWSPDIWeb/LocalizedResources.cs index ae57dec..0a5abed 100644 --- a/Source/EWSPDIWeb/LocalizedResources.cs +++ b/Source/EWSPDIWeb/LocalizedResources.cs @@ -2,9 +2,8 @@ // System : EWSoftware.PDI ASP.NET Web Server Controls // File : LocalizedResources.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains some internal classes used to manage the localized resources for the assembly // @@ -18,11 +17,10 @@ // 01/24/2004 EFW Created the code //=============================================================================================================== -using System; using System.Reflection; using System.Resources; -namespace EWSoftware.PDI +namespace EWSoftware.PDI.Web.Controls { /// /// This class is used to load resources for the assembly @@ -37,10 +35,10 @@ internal static class LR private const string ResourcesKey = "PDIWebControls"; // The resource manager - private static ResourceManager rm; + private static ResourceManager rm = null!; // This is a helper object used to quickly lock the class when creating the resource manager - private static readonly object syncRoot = new Object(); + private static readonly object syncRoot = new(); #endregion @@ -83,12 +81,7 @@ private static ResourceManager Resources /// "[?:<key>]" if not found. internal static string GetString(string name) { - string s = Resources.GetString(name, null); - - if(s == null) - s = $"[?:{name}]"; - - return s; + return Resources.GetString(name, null) ?? $"[?:{name}]"; } #endregion } diff --git a/Source/EWSPDIWeb/ReadMe.txt b/Source/EWSPDIWeb/ReadMe.md similarity index 79% rename from Source/EWSPDIWeb/ReadMe.txt rename to Source/EWSPDIWeb/ReadMe.md index ff1752f..123527e 100644 --- a/Source/EWSPDIWeb/ReadMe.txt +++ b/Source/EWSPDIWeb/ReadMe.md @@ -1,5 +1,4 @@ -EWSoftware.PDI.Web.Controls Library ------------------------------------ +# EWSoftware.PDI.Web.Controls Library This library contains some web controls that can be used to edit recurrence settings. See the online help content for usage and API information: http://EWSoftware.github.io/PDI/index.html diff --git a/Source/EWSPDIWeb/RecurrencePattern.bmp b/Source/EWSPDIWeb/RecurrencePattern.bmp deleted file mode 100644 index e257305ef1ccfb838f6876816e2d8b8aaeda1c7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcmYLBxedfH4ATJt;_}AG9O<)5s-sGE_AHsgQ>FEhwu8_j^-%JD+&1uI+Q{$Z$ChqH z*CCHLIywxC7>UZ#YOTyNS`TYY70IU&<(j|?9jt(-Qc4DbBs@_HaI$sF9;z*IIfDl< U`7zg-{khRtH~dX2r [DefaultProperty("ShowCanOccurOnHoliday"), ToolboxData("<{0}:RecurrencePattern runat=server />"), Designer(typeof(RecurrencePatternDesigner)), ParseChildren(true)] - public class RecurrencePattern : System.Web.UI.Control, INamingContainer, IPostBackDataHandler + public class RecurrencePattern : Control, INamingContainer, IPostBackDataHandler { #region Private data members //===================================================================== @@ -59,14 +58,11 @@ public class RecurrencePattern : System.Web.UI.Control, INamingContainer, IPostB internal const string RecurrencePatternScripts = "EWSoftware.PDI.Web.Controls.Scripts."; // The current recurrence pattern - private Recurrence rRecur; + private Recurrence rRecur = null!; // Set focus flag private bool setFocusToPattern; - // The validator - private CustomValidator validator; - #endregion #region Properties @@ -181,7 +177,7 @@ public bool ShowWeekStartDay get { object oShowWeekStartDay = this.ViewState["ShowWSD"]; - return (oShowWeekStartDay == null) ? true : (bool)oShowWeekStartDay; + return oShowWeekStartDay == null || (bool)oShowWeekStartDay; } set => this.ViewState["ShowWSD"] = value; } @@ -199,7 +195,7 @@ public bool ShowCanOccurOnHoliday get { object oShowHoliday = this.ViewState["ShowHol"]; - return (oShowHoliday == null) ? true : (bool)oShowHoliday; + return oShowHoliday == null || (bool)oShowHoliday; } set => this.ViewState["ShowHol"] = value; } @@ -218,7 +214,7 @@ public bool ShowAdvanced get { object oShowAdvanced = this.ViewState["ShowAdv"]; - return (oShowAdvanced == null) ? true : (bool)oShowAdvanced; + return oShowAdvanced == null || (bool)oShowAdvanced; } set => this.ViewState["ShowAdv"] = value; } @@ -479,7 +475,7 @@ private void ParseAdvancedOptions(string[] options) { int idx, instance; string dayPart; - string[] dayInstances, days = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" }; + string[] dayInstances, days = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"]; rRecur.Frequency = (RecurFrequency)Convert.ToInt32(options[1], CultureInfo.InvariantCulture); rRecur.Interval = Convert.ToInt32(options[2], CultureInfo.InvariantCulture); @@ -528,7 +524,7 @@ private void ParseAdvancedOptions(string[] options) internal string RenderAtDesignTime() { Assembly asm = Assembly.GetExecutingAssembly(); - StringBuilder sb = new StringBuilder(4096); + StringBuilder sb = new(4096); using(var sr = new StreamReader(asm.GetManifestResourceStream(RecurrencePatternHtml + "RecurrencePattern.html"))) @@ -602,7 +598,7 @@ internal string RenderAtDesignTime() public bool LoadPostData(string postDataKey, NameValueCollection postCollection) { string[] options; - string pattern = null; + string? pattern = null; DaysOfWeek daysOfWeek = DaysOfWeek.None; int val; @@ -613,7 +609,7 @@ public bool LoadPostData(string postDataKey, NameValueCollection postCollection) { // Parse and load the recurrence rRecur = new Recurrence(); - options = pattern.Split('\xFF'); + options = pattern!.Split('\xFF'); // Parse the pattern options if(options[0] == "1") @@ -713,8 +709,8 @@ public bool LoadPostData(string postDataKey, NameValueCollection postCollection) // Every week day rRecur.Frequency = RecurFrequency.Daily; rRecur.Interval = 1; - rRecur.ByDay.AddRange(new [] { DayOfWeek.Monday, DayOfWeek.Tuesday, - DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday }); + rRecur.ByDay.AddRange([ DayOfWeek.Monday, DayOfWeek.Tuesday, + DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday ]); } else rRecur.RecurDaily(Convert.ToInt32(options[3], CultureInfo.InvariantCulture)); @@ -771,7 +767,7 @@ protected override void CreateChildControls() return; Assembly asm = Assembly.GetExecutingAssembly(); - StringBuilder sb = new StringBuilder(4096); + StringBuilder sb = new(4096); if(rRecur == null) { @@ -880,7 +876,7 @@ protected override void CreateChildControls() String.IsNullOrWhiteSpace(this.CssPanelBody) || String.IsNullOrWhiteSpace(this.CssPanelHeading) || String.IsNullOrWhiteSpace(this.CssPanelTitle) || String.IsNullOrWhiteSpace(this.CssSelect)) { - LiteralControl cssLink = new LiteralControl(String.Format(CultureInfo.InvariantCulture, + LiteralControl cssLink = new(String.Format(CultureInfo.InvariantCulture, "", this.Page.ClientScript.GetWebResourceUrl(typeof(RecurrencePattern), RecurrencePattern.RecurrencePatternHtml + "RecurrenceStyle.css"))) @@ -900,7 +896,7 @@ protected override void CreateChildControls() // Page_ClientValidate function for __doPostBack (added by OnPreRender). if(this.DetermineRenderUplevel) { - validator = new CustomValidator + var validator = new CustomValidator { ID = this.ID + "_Validator", ClientValidationFunction = this.ID + "_Validate", @@ -911,10 +907,10 @@ protected override void CreateChildControls() this.Controls.Add(validator); } else - this.Page.ClientScript.RegisterOnSubmitStatement(typeof(RecurrencePattern), this.ID + "_Submit", + this.Page!.ClientScript.RegisterOnSubmitStatement(typeof(RecurrencePattern), this.ID + "_Submit", "return RP_" + this.ID + ".ValidateRecurrence();"); - this.Page.RegisterRequiresPostBack(this); + this.Page!.RegisterRequiresPostBack(this); } /// @@ -924,7 +920,7 @@ protected override void CreateChildControls() /// The event arguments protected override void OnPreRender(EventArgs e) { - StringBuilder sb = new StringBuilder(1024); + StringBuilder sb = new(1024); string patternId; int range; @@ -1072,7 +1068,7 @@ protected override void OnPreRender(EventArgs e) public void GetRecurrence(Recurrence recurrence) { if(recurrence == null) - throw new ArgumentNullException("recurrence", LR.GetString("ExRPRecurrenceIsNull")); + throw new ArgumentNullException(nameof(recurrence), LR.GetString("ExRPRecurrenceIsNull")); recurrence.Parse(rRecur.ToString()); } diff --git a/Source/EWSPDIWeb/RecurrencePattern.png b/Source/EWSPDIWeb/RecurrencePattern.png new file mode 100644 index 0000000000000000000000000000000000000000..6090bfa9b203fde694df434fd7ae8eb807d6e5a9 GIT binary patch literal 524 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|m0G|-oM~@yYU9vPJI7Cxj^VF$R@p19lS=nn=uep8u_VQ)R_wCyURJdWo z22)ehqM{-oJ4@lm86YK4666>B9~Ce>P>z)Z%5fHWL>4nJ@ErzW#^d=bQh8ZuQ0pzeUNHMZ9FalX# zKr9VqgM6vM$P5-|0@05M2Ej7GDR0T@mb*cn)WDh!N_ z4Hy?dOavp@3Xlx~Oh9v(z$$|*Er2YjE<*zYknGE=-z-ku%Bcb}lRaG=Lo|YO z`=j{|C~&Yaipp=f`}_X3gIU74-hYIVxJ^?$3F}Radv`{-!6)c`0*w3_cuF QssmZ=>FVdQ&MBb@0Pks(o&W#< literal 0 HcmV?d00001 diff --git a/Source/EWSPDIWeb/RecurrencePatternDesigner.cs b/Source/EWSPDIWeb/RecurrencePatternDesigner.cs index f852c58..93381c1 100644 --- a/Source/EWSPDIWeb/RecurrencePatternDesigner.cs +++ b/Source/EWSPDIWeb/RecurrencePatternDesigner.cs @@ -2,9 +2,8 @@ // System : EWSoftware.PDI ASP.NET Web Server Controls // File : RecurrencePatternDesigner.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/14/2014 -// Note : Copyright 2005-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2005-2025, Eric Woodruff, All rights reserved // // This file contains a designer for the recurrence pattern control // @@ -29,33 +28,30 @@ namespace EWSoftware.PDI.Web.Design { /// /// This provides design time support for the web server - /// control. + /// control. /// internal sealed class RecurrencePatternDesigner : System.Web.UI.Design.ControlDesigner { /// - /// This returns the design time HTML for the + /// This returns the design time HTML for the /// control. /// /// The design time HTML public override string GetDesignTimeHtml() { - EWSoftware.PDI.Web.Controls.RecurrencePattern rp = (RecurrencePattern)this.Component; + RecurrencePattern rp = (RecurrencePattern)this.Component; bool isVisible = rp.Visible; try { - using(var tw = new StringWriter(CultureInfo.InvariantCulture)) - { - using(var writer = new HtmlTextWriter(tw)) - { - if(!isVisible) - rp.Visible = true; + using var tw = new StringWriter(CultureInfo.InvariantCulture); + using var writer = new HtmlTextWriter(tw); + + if(!isVisible) + rp.Visible = true; - writer.Write(rp.RenderAtDesignTime()); - return tw.ToString(); - } - } + writer.Write(rp.RenderAtDesignTime()); + return tw.ToString(); } catch(Exception e) { diff --git a/Source/EWSPDIWinForms/AdvancedPattern.cs b/Source/EWSPDIWinForms/AdvancedPattern.cs index 691de96..4107879 100644 --- a/Source/EWSPDIWinForms/AdvancedPattern.cs +++ b/Source/EWSPDIWinForms/AdvancedPattern.cs @@ -2,9 +2,8 @@ // System : EWSoftware.PDI Windows Forms Controls // File : AdvancedPattern.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/14/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains one of several user controls that are combined to allow the editing of various recurrence // parameters. This one is used to specify the settings for an advanced pattern that uses a more complex @@ -42,7 +41,7 @@ internal sealed partial class AdvancedPattern : System.Windows.Forms.UserControl private RecurFrequency rf; // Day instances for the ByDay option with and without instances - private DayInstanceCollection dicWithInst, dicDayOnly; + private readonly DayInstanceCollection dicWithInst, dicDayOnly; #endregion @@ -54,8 +53,8 @@ internal sealed partial class AdvancedPattern : System.Windows.Forms.UserControl /// public AdvancedPattern() { - dicWithInst = new DayInstanceCollection(); - dicDayOnly = new DayInstanceCollection(); + dicWithInst = []; + dicDayOnly = []; InitializeComponent(); @@ -237,12 +236,12 @@ public void SetValues(Recurrence recurrence) /// /// The sender of the event /// The event parameters - private void btnAdd_Click(object sender, System.EventArgs e) + private void btnAdd_Click(object sender, EventArgs e) { if(udcDayInstance.Enabled) - dicWithInst.Add((int)udcDayInstance.Value, (DayOfWeek)cboDOW.SelectedValue); + dicWithInst.Add((int)udcDayInstance.Value, (DayOfWeek)cboDOW.SelectedValue!); - dicDayOnly.Add((DayOfWeek)cboDOW.SelectedValue); + dicDayOnly.Add((DayOfWeek)cboDOW.SelectedValue!); LoadByDayValues(); } @@ -252,15 +251,17 @@ private void btnAdd_Click(object sender, System.EventArgs e) /// /// The sender of the event /// The event parameters - private void btnRemove_Click(object sender, System.EventArgs e) + private void btnRemove_Click(object sender, EventArgs e) { if(lbByDay.SelectedIndex == -1) lbByDay.SelectedIndex = 0; else + { if(udcDayInstance.Enabled) dicWithInst.RemoveAt(lbByDay.SelectedIndex); else dicDayOnly.RemoveAt(lbByDay.SelectedIndex); + } LoadByDayValues(); } @@ -270,7 +271,7 @@ private void btnRemove_Click(object sender, System.EventArgs e) /// /// The sender of the event /// The event parameters - private void btnClear_Click(object sender, System.EventArgs e) + private void btnClear_Click(object sender, EventArgs e) { dicWithInst.Clear(); dicDayOnly.Clear(); @@ -282,7 +283,7 @@ private void btnClear_Click(object sender, System.EventArgs e) /// /// The sender of the event /// The event parameters - private void SetDayInstanceEnabledState(object sender, System.EventArgs e) + private void SetDayInstanceEnabledState(object sender, EventArgs e) { bool newState = udcDayInstance.Enabled; @@ -294,8 +295,10 @@ private void SetDayInstanceEnabledState(object sender, System.EventArgs e) newState = (txtByWeekNo.Text.Length == 0); } else + { if(rf == RecurFrequency.Monthly) newState = (txtByMonthDay.Text.Length == 0); + } if(udcDayInstance.Enabled != newState) { diff --git a/Source/EWSPDIWinForms/BrowseControl.bmp b/Source/EWSPDIWinForms/BrowseControl.bmp deleted file mode 100644 index 9ef02fd9706007648094c6753ddeecdfecb69a22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcma(}u@Qhk2*W$?XdS~j?A?XRZ<)s_n93FdJhkRY0_2b5e5i22c5s_qXw5)VOFF9w q35rz9plHd=;1PHhxkm@$#R_syjGtf`SxmwL!8s0T?|uLKI{N}wDn>&9 diff --git a/Source/EWSPDIWinForms/BrowseControl.png b/Source/EWSPDIWinForms/BrowseControl.png new file mode 100644 index 0000000000000000000000000000000000000000..cd88f69e48857d32cf94a8bf17c136ca4eac5133 GIT binary patch literal 411 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G}c0G|-o0|yQOnLyAhZ)5_bm`j5Eg8%<#xPFQksFs1Vz$3Dlfr0NZ2s0kf zUy%Y7lqhkHC<)F_D=AMbN@WO0%*-p%^K%VRFx4~EGy1)Uc^gp8w$upEG*3@01`Z&H zl|hP;m4Ok+@&aOMC>!Kr4Mt|LI1`X<$jAitK@^ak+0FtM&jPYRAOVO$`e8Jhr3^qn zPhe+Y0je-CGB#jb05KJ$gLMJKq$xl)2rvQ7VFIfRva|rQpt=kV3_!9kuYR*Qbt|U| z$W-%maSYK2PEJ_Bl;Gmt!_$+%vebb^qJc$$$A^(e_eI+!7K4S1461(^VvW}v0EG*K Mr>mdKI;Vst0Mmj@+yDRo literal 0 HcmV?d00001 diff --git a/Source/EWSPDIWinForms/DailyPattern.cs b/Source/EWSPDIWinForms/DailyPattern.cs index d333096..03f75db 100644 --- a/Source/EWSPDIWinForms/DailyPattern.cs +++ b/Source/EWSPDIWinForms/DailyPattern.cs @@ -2,9 +2,8 @@ // System : EWSoftware.PDI Windows Forms Controls // File : DailyPattern.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/17/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains one of several user controls that are combined to allow the editing of various recurrence // parameters. This one is used to specify the settings for a daily recurrence pattern. @@ -21,7 +20,6 @@ using System; using System.ComponentModel; -using System.Windows.Forms; namespace EWSoftware.PDI.Windows.Forms { @@ -54,14 +52,16 @@ public DailyPattern() public void GetValues(Recurrence recurrence) { if(recurrence.Frequency == RecurFrequency.Daily) + { if(rbEveryXDays.Checked) recurrence.Interval = (int)udcDays.Value; else { recurrence.Interval = 1; - recurrence.ByDay.AddRange(new[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, - DayOfWeek.Thursday, DayOfWeek.Friday }); + recurrence.ByDay.AddRange([ DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, + DayOfWeek.Thursday, DayOfWeek.Friday ]); } + } } /// @@ -84,9 +84,13 @@ public void SetValues(Recurrence recurrence) if(recurrence.ByDay.Count == 5 && recurrence.Interval == 1) { for(idx = 0; idx < 5; idx++) + { if(recurrence.ByDay[idx].Instance != 0 || recurrence.ByDay[idx].DayOfWeek == DayOfWeek.Saturday || recurrence.ByDay[idx].DayOfWeek == DayOfWeek.Sunday) + { break; + } + } rbEveryWeekday.Checked = (idx == 5); } @@ -100,9 +104,9 @@ public void SetValues(Recurrence recurrence) /// /// Enable or disable the days text box based on the selection /// - private void Daily_CheckedChanged(object sender, System.EventArgs e) + private void Daily_CheckedChanged(object sender, EventArgs e) { - udcDays.Enabled = ((sender as RadioButton) == rbEveryXDays); + udcDays.Enabled = sender == rbEveryXDays; } #endregion } diff --git a/Source/EWSPDIWinForms/EWSoftware.PDI.Windows.Forms.csproj b/Source/EWSPDIWinForms/EWSoftware.PDI.Windows.Forms.csproj index 1abb231..f8299c8 100644 --- a/Source/EWSPDIWinForms/EWSoftware.PDI.Windows.Forms.csproj +++ b/Source/EWSPDIWinForms/EWSoftware.PDI.Windows.Forms.csproj @@ -1,17 +1,17 @@  - net6.0-windows;net40 + net8.0-windows;net40 true True true Eric Woodruff EWSoftware Personal Data Interchange Library EWSoftware PDI Windows Forms Control Library - Copyright (c) 2003-2023, Eric Woodruff, All Rights Reserved + Copyright (c) 2003-2025, Eric Woodruff, All Rights Reserved en - 2023.1.2.0 - 23.1.2.0 + 2025.1.9.0 + 25.1.9.0 This library contains some Windows Forms controls that can be used to edit holiday calculation settings and to edit recurrence settings. See the project website for the code, a help file, and demos. Eric Woodruff https://raw.githubusercontent.com/EWSoftware/PDI/master/EWSPDI.png @@ -22,18 +22,26 @@ https://github.com/EWSoftware/PDI MS-PL Targets .NET Framework 4.0 and later and .NET 6.0 and later (Windows platform only) - true + ReadMe.md False False False False + true ..\EWSPDI.snk true AllEnabledByDefault pdbonly true + latest + enable + + + + + @@ -44,28 +52,19 @@ - - - - + + + - - - - - - true - \ - - - - + + + diff --git a/Source/EWSPDIWinForms/GlobalSuppressions.cs b/Source/EWSPDIWinForms/GlobalSuppressions.cs index 85a310e7efee5c9df7add1312045253923cfcfd8..be554784989646ea1b3cd0c4b91f0d277b81b123 100644 GIT binary patch delta 16 YcmeCMTw=Lloy24ZA(_qVByKSS066sqYybcN delta 12 TcmZ2t* Holidays holidays.Clear(); if(value != null) + { foreach(Holiday h in value) holidays.Add((Holiday)h.Clone()); + } this.LoadHolidayList(); } @@ -102,7 +104,7 @@ public HolidayManager() { InitializeComponent(); - holidays = new HolidayCollection(); + holidays = []; this.Defaults = new HolidayCollection().AddStandardHolidays(); @@ -127,10 +129,12 @@ private void LoadHolidayList() if(holidays.Count > 0) { if(lastIdx > -1) + { if(lastIdx < lbHolidays.Items.Count) lbHolidays.SelectedIndex = lastIdx; else lbHolidays.SelectedIndex = lbHolidays.Items.Count - 1; + } btnEdit.Enabled = true; btnRemove.Enabled = true; @@ -151,22 +155,21 @@ private void LoadHolidayList() /// /// Add a new holiday to the list box /// - private void btnAdd_Click(object sender, System.EventArgs e) + private void btnAdd_Click(object sender, EventArgs e) { - using(HolidayPropertiesDlg dlg = new HolidayPropertiesDlg()) + using HolidayPropertiesDlg dlg = new(); + + if(dlg.ShowDialog() == DialogResult.OK) { - if(dlg.ShowDialog() == DialogResult.OK) - { - holidays.Add(dlg.HolidayInfo); - this.LoadHolidayList(); - } + holidays.Add(dlg.HolidayInfo); + this.LoadHolidayList(); } } /// /// Edit a holiday entry in the list box /// - private void btnEdit_Click(object sender, System.EventArgs e) + private void btnEdit_Click(object sender, EventArgs e) { if(lbHolidays.SelectedIndex == -1) { @@ -174,25 +177,24 @@ private void btnEdit_Click(object sender, System.EventArgs e) return; } - using(HolidayPropertiesDlg dlg = new HolidayPropertiesDlg()) - { - // The dialog takes care loading data from the object - dlg.HolidayInfo = holidays[lbHolidays.SelectedIndex]; + using HolidayPropertiesDlg dlg = new(); - if(dlg.ShowDialog() == DialogResult.OK) - { - // Replace the holiday with the edited information. Because the type may change, the - // add/edit dialog returns a new instance. - holidays[lbHolidays.SelectedIndex] = dlg.HolidayInfo; - this.LoadHolidayList(); - } + // The dialog takes care loading data from the object + dlg.HolidayInfo = holidays[lbHolidays.SelectedIndex]; + + if(dlg.ShowDialog() == DialogResult.OK) + { + // Replace the holiday with the edited information. Because the type may change, the + // add/edit dialog returns a new instance. + holidays[lbHolidays.SelectedIndex] = dlg.HolidayInfo; + this.LoadHolidayList(); } } /// /// Delete a holiday from the list box /// - private void btnRemove_Click(object sender, System.EventArgs e) + private void btnRemove_Click(object sender, EventArgs e) { if(lbHolidays.SelectedIndex == -1) MessageBox.Show(LR.GetString("EditHMSelectHoliday")); @@ -206,7 +208,7 @@ private void btnRemove_Click(object sender, System.EventArgs e) /// /// Clear all holidays from the list box /// - private void btnClear_Click(object sender, System.EventArgs e) + private void btnClear_Click(object sender, EventArgs e) { holidays.Clear(); this.LoadHolidayList(); @@ -215,13 +217,15 @@ private void btnClear_Click(object sender, System.EventArgs e) /// /// Clear all holidays and add the default set as defined by the property /// - private void btnDefault_Click(object sender, System.EventArgs e) + private void btnDefault_Click(object sender, EventArgs e) { holidays.Clear(); if(this.Defaults != null) + { foreach(Holiday h in this.Defaults) holidays.Add((Holiday)h.Clone()); + } this.LoadHolidayList(); } @@ -229,57 +233,54 @@ private void btnDefault_Click(object sender, System.EventArgs e) /// /// Load the holiday info from a file in the format selected by the user /// - private void btnLoad_Click(object sender, System.EventArgs e) + private void btnLoad_Click(object sender, EventArgs e) { - using(OpenFileDialog dlg = new OpenFileDialog()) + using OpenFileDialog dlg = new() { - dlg.Title = LR.GetString("HMLoadTitle"); - dlg.DefaultExt = "xml"; - dlg.Filter = LR.GetString("HMFileDlgFilter"); - dlg.InitialDirectory = Environment.CurrentDirectory; + Title = LR.GetString("HMLoadTitle"), + DefaultExt = "xml", + Filter = LR.GetString("HMFileDlgFilter"), + InitialDirectory = Environment.CurrentDirectory + }; - if(dlg.ShowDialog() == DialogResult.OK) + if(dlg.ShowDialog() == DialogResult.OK) + { + // Deserialize the holidays from a file of the selected format + try { - // Deserialize the holidays from a file of the selected format - try - { - this.Cursor = Cursors.WaitCursor; - - using(FileStream fs = new FileStream(dlg.FileName, FileMode.Open)) - { - XmlSerializer xs = new XmlSerializer(typeof(HolidayCollection)); - - using(var rdr = XmlReader.Create(fs)) - { - holidays = (HolidayCollection)xs.Deserialize(rdr); - } - } + this.Cursor = Cursors.WaitCursor; - this.LoadHolidayList(); - } - catch(Exception ex) - { - System.Diagnostics.Debug.Write(ex.ToString()); + using FileStream fs = new(dlg.FileName, FileMode.Open); + XmlSerializer xs = new(typeof(HolidayCollection)); - string errorMsg = LR.GetString("HMLoadError", ex.Message); + using var rdr = XmlReader.Create(fs); - if(ex.InnerException != null) - { - errorMsg += ex.InnerException.Message + "\n"; + holidays = (HolidayCollection)xs.Deserialize(rdr)!; - if(ex.InnerException.InnerException != null) - errorMsg += ex.InnerException.InnerException.Message; - } + this.LoadHolidayList(); + } + catch(Exception ex) + { + System.Diagnostics.Debug.Write(ex.ToString()); - System.Diagnostics.Debug.WriteLine(errorMsg); + string errorMsg = LR.GetString("HMLoadError", ex.Message); - MessageBox.Show(errorMsg, LR.GetString("HMErrorLoading"), MessageBoxButtons.OK, - MessageBoxIcon.Error); - } - finally + if(ex.InnerException != null) { - this.Cursor = Cursors.Default; + errorMsg += ex.InnerException.Message + "\n"; + + if(ex.InnerException.InnerException != null) + errorMsg += ex.InnerException.InnerException.Message; } + + System.Diagnostics.Debug.WriteLine(errorMsg); + + MessageBox.Show(errorMsg, LR.GetString("HMErrorLoading"), MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + finally + { + this.Cursor = Cursors.Default; } } } @@ -289,49 +290,48 @@ private void btnLoad_Click(object sender, System.EventArgs e) /// private void btnSave_Click(object sender, System.EventArgs e) { - using(SaveFileDialog dlg = new SaveFileDialog()) + using SaveFileDialog dlg = new() { - dlg.Title = LR.GetString("HMSaveTitle"); - dlg.DefaultExt = "xml"; - dlg.Filter = LR.GetString("HMFileDlgFilter"); - dlg.InitialDirectory = Environment.CurrentDirectory; + Title = LR.GetString("HMSaveTitle"), + DefaultExt = "xml", + Filter = LR.GetString("HMFileDlgFilter"), + InitialDirectory = Environment.CurrentDirectory + }; - if(dlg.ShowDialog() == DialogResult.OK) + if(dlg.ShowDialog() == DialogResult.OK) + { + // Serialize the holidays to a file of the selected format + try { - // Serialize the holidays to a file of the selected format - try - { - this.Cursor = Cursors.WaitCursor; + this.Cursor = Cursors.WaitCursor; - using(FileStream fs = new FileStream(dlg.FileName, FileMode.Create)) - { - XmlSerializer xs = new XmlSerializer(typeof(HolidayCollection)); - xs.Serialize(fs, holidays); - } - } - catch(Exception ex) - { - System.Diagnostics.Debug.Write(ex.ToString()); + using FileStream fs = new(dlg.FileName, FileMode.Create); + XmlSerializer xs = new(typeof(HolidayCollection)); + + xs.Serialize(fs, holidays); + } + catch(Exception ex) + { + System.Diagnostics.Debug.Write(ex.ToString()); - string errorMsg = LR.GetString("HMSaveError", ex.Message); + string errorMsg = LR.GetString("HMSaveError", ex.Message); - if(ex.InnerException != null) - { - errorMsg += ex.InnerException.Message + "\n"; + if(ex.InnerException != null) + { + errorMsg += ex.InnerException.Message + "\n"; - if(ex.InnerException.InnerException != null) - errorMsg += ex.InnerException.InnerException.Message; - } + if(ex.InnerException.InnerException != null) + errorMsg += ex.InnerException.InnerException.Message; + } - System.Diagnostics.Debug.WriteLine(errorMsg); + System.Diagnostics.Debug.WriteLine(errorMsg); - MessageBox.Show(errorMsg, LR.GetString("HMErrorSaving"), MessageBoxButtons.OK, - MessageBoxIcon.Error); - } - finally - { - this.Cursor = Cursors.Default; - } + MessageBox.Show(errorMsg, LR.GetString("HMErrorSaving"), MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + finally + { + this.Cursor = Cursors.Default; } } } diff --git a/Source/EWSPDIWinForms/HolidayManager.png b/Source/EWSPDIWinForms/HolidayManager.png new file mode 100644 index 0000000000000000000000000000000000000000..872668d5d7bebcadfeaa72fd7fad3bda2e618a2b GIT binary patch literal 482 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G}%0G|+7hX4N=8XAB+h6W(raNxiJAm=|&kb%J}->(fwah3%61p`IEfFanw zLI@;S;1OBOz`%DHgc*%FBlnwHU1|u_AoC(M_WMl&SEDFfZY-a(B zX93wDkO0IW{V*EMQU+jHOkihV0je-CGB#jb05KJ$gLMJKq$xl)2rvQ7VFIfRva|rQ zpt=kV3_!9kuYR*Qbt|U|$PD##aSYK2p4#Whcff$-$On@t|NbAn>Jqu?j+KW@kE6>U z4jG3_Zbdivn$DRxhId3T#8&Jno26i9&b&L%l56MvCnlHNnwEz~Dz8vFl`t(za?KL^ a>b^a7qD-3B=W8B=Ec0~rb6Mw<&;$T47 - /// Required method for Designer support - do not modify the contents of this method with the code editor - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); + /// + /// Required method for Designer support - do not modify the contents of this method with the code editor + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HolidayPropertiesDlg)); - this.btnOK = new System.Windows.Forms.Button(); - this.btnCancel = new System.Windows.Forms.Button(); - this.label1 = new System.Windows.Forms.Label(); - this.txtDescription = new System.Windows.Forms.TextBox(); - this.label2 = new System.Windows.Forms.Label(); - this.rbFloating = new System.Windows.Forms.RadioButton(); - this.rbFixed = new System.Windows.Forms.RadioButton(); - this.label3 = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.cboOccurrence = new System.Windows.Forms.ComboBox(); - this.label5 = new System.Windows.Forms.Label(); - this.label6 = new System.Windows.Forms.Label(); - this.cboDayOfWeek = new System.Windows.Forms.ComboBox(); - this.cboMonth = new System.Windows.Forms.ComboBox(); - this.epErrors = new System.Windows.Forms.ErrorProvider(this.components); - this.chkAdjustDate = new System.Windows.Forms.CheckBox(); - this.udcOffset = new System.Windows.Forms.NumericUpDown(); - this.udcDayOfMonth = new System.Windows.Forms.NumericUpDown(); - this.udcMinimumYear = new System.Windows.Forms.NumericUpDown(); - this.label7 = new System.Windows.Forms.Label(); - this.udcMaximumYear = new System.Windows.Forms.NumericUpDown(); - this.label8 = new System.Windows.Forms.Label(); - ((System.ComponentModel.ISupportInitialize)(this.epErrors)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.udcOffset)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.udcDayOfMonth)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.udcMinimumYear)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.udcMaximumYear)).BeginInit(); + btnOK = new System.Windows.Forms.Button(); + btnCancel = new System.Windows.Forms.Button(); + label1 = new System.Windows.Forms.Label(); + txtDescription = new System.Windows.Forms.TextBox(); + label2 = new System.Windows.Forms.Label(); + rbFloating = new System.Windows.Forms.RadioButton(); + rbFixed = new System.Windows.Forms.RadioButton(); + label3 = new System.Windows.Forms.Label(); + label4 = new System.Windows.Forms.Label(); + cboOccurrence = new System.Windows.Forms.ComboBox(); + label5 = new System.Windows.Forms.Label(); + label6 = new System.Windows.Forms.Label(); + cboDayOfWeek = new System.Windows.Forms.ComboBox(); + cboMonth = new System.Windows.Forms.ComboBox(); + epErrors = new System.Windows.Forms.ErrorProvider(components); + chkAdjustDate = new System.Windows.Forms.CheckBox(); + udcOffset = new System.Windows.Forms.NumericUpDown(); + udcDayOfMonth = new System.Windows.Forms.NumericUpDown(); + udcMinimumYear = new System.Windows.Forms.NumericUpDown(); + label7 = new System.Windows.Forms.Label(); + udcMaximumYear = new System.Windows.Forms.NumericUpDown(); + label8 = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)epErrors).BeginInit(); + ((System.ComponentModel.ISupportInitialize)udcOffset).BeginInit(); + ((System.ComponentModel.ISupportInitialize)udcDayOfMonth).BeginInit(); + ((System.ComponentModel.ISupportInitialize)udcMinimumYear).BeginInit(); + ((System.ComponentModel.ISupportInitialize)udcMaximumYear).BeginInit(); this.SuspendLayout(); // // btnOK // - this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; - resources.ApplyResources(this.btnOK, "btnOK"); - this.btnOK.Name = "btnOK"; + btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + resources.ApplyResources(btnOK, "btnOK"); + btnOK.Name = "btnOK"; // // btnCancel // - this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - resources.ApplyResources(this.btnCancel, "btnCancel"); - this.btnCancel.Name = "btnCancel"; + btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + resources.ApplyResources(btnCancel, "btnCancel"); + btnCancel.Name = "btnCancel"; // // label1 // - resources.ApplyResources(this.label1, "label1"); - this.label1.Name = "label1"; + resources.ApplyResources(label1, "label1"); + label1.Name = "label1"; // // txtDescription // - resources.ApplyResources(this.txtDescription, "txtDescription"); - this.txtDescription.Name = "txtDescription"; + resources.ApplyResources(txtDescription, "txtDescription"); + txtDescription.Name = "txtDescription"; // // label2 // - resources.ApplyResources(this.label2, "label2"); - this.label2.Name = "label2"; + resources.ApplyResources(label2, "label2"); + label2.Name = "label2"; // // rbFloating // - resources.ApplyResources(this.rbFloating, "rbFloating"); - this.rbFloating.Name = "rbFloating"; - this.rbFloating.CheckedChanged += new System.EventHandler(this.Type_CheckedChanged); + resources.ApplyResources(rbFloating, "rbFloating"); + rbFloating.Name = "rbFloating"; + rbFloating.CheckedChanged += this.Type_CheckedChanged; // // rbFixed // - resources.ApplyResources(this.rbFixed, "rbFixed"); - this.rbFixed.Name = "rbFixed"; - this.rbFixed.CheckedChanged += new System.EventHandler(this.Type_CheckedChanged); + resources.ApplyResources(rbFixed, "rbFixed"); + rbFixed.Name = "rbFixed"; + rbFixed.CheckedChanged += this.Type_CheckedChanged; // // label3 // - resources.ApplyResources(this.label3, "label3"); - this.label3.Name = "label3"; + resources.ApplyResources(label3, "label3"); + label3.Name = "label3"; // // label4 // - resources.ApplyResources(this.label4, "label4"); - this.label4.Name = "label4"; + resources.ApplyResources(label4, "label4"); + label4.Name = "label4"; // // cboOccurrence // - this.cboOccurrence.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - resources.ApplyResources(this.cboOccurrence, "cboOccurrence"); - this.cboOccurrence.Name = "cboOccurrence"; + cboOccurrence.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + resources.ApplyResources(cboOccurrence, "cboOccurrence"); + cboOccurrence.Name = "cboOccurrence"; // // label5 // - resources.ApplyResources(this.label5, "label5"); - this.label5.Name = "label5"; + resources.ApplyResources(label5, "label5"); + label5.Name = "label5"; // // label6 // - resources.ApplyResources(this.label6, "label6"); - this.label6.Name = "label6"; + resources.ApplyResources(label6, "label6"); + label6.Name = "label6"; // // cboDayOfWeek // - this.cboDayOfWeek.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - resources.ApplyResources(this.cboDayOfWeek, "cboDayOfWeek"); - this.cboDayOfWeek.Name = "cboDayOfWeek"; + cboDayOfWeek.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + resources.ApplyResources(cboDayOfWeek, "cboDayOfWeek"); + cboDayOfWeek.Name = "cboDayOfWeek"; // // cboMonth // - this.cboMonth.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - resources.ApplyResources(this.cboMonth, "cboMonth"); - this.cboMonth.Name = "cboMonth"; + cboMonth.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + resources.ApplyResources(cboMonth, "cboMonth"); + cboMonth.Name = "cboMonth"; // // epErrors // - this.epErrors.ContainerControl = this; + epErrors.ContainerControl = this; // // chkAdjustDate // - resources.ApplyResources(this.chkAdjustDate, "chkAdjustDate"); - this.chkAdjustDate.Name = "chkAdjustDate"; + resources.ApplyResources(chkAdjustDate, "chkAdjustDate"); + chkAdjustDate.Name = "chkAdjustDate"; // // udcOffset // - resources.ApplyResources(this.udcOffset, "udcOffset"); - this.udcOffset.Maximum = new decimal(new int[] { - 999, - 0, - 0, - 0}); - this.udcOffset.Minimum = new decimal(new int[] { - 999, - 0, - 0, - -2147483648}); - this.udcOffset.Name = "udcOffset"; - this.udcOffset.Value = new decimal(new int[] { - 1, - 0, - 0, - 0}); + resources.ApplyResources(udcOffset, "udcOffset"); + udcOffset.Maximum = new decimal(new int[] { 999, 0, 0, 0 }); + udcOffset.Minimum = new decimal(new int[] { 999, 0, 0, System.Int32.MinValue }); + udcOffset.Name = "udcOffset"; + udcOffset.Value = new decimal(new int[] { 1, 0, 0, 0 }); // // udcDayOfMonth // - resources.ApplyResources(this.udcDayOfMonth, "udcDayOfMonth"); - this.udcDayOfMonth.Maximum = new decimal(new int[] { - 31, - 0, - 0, - 0}); - this.udcDayOfMonth.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.udcDayOfMonth.Name = "udcDayOfMonth"; - this.udcDayOfMonth.Value = new decimal(new int[] { - 1, - 0, - 0, - 0}); + resources.ApplyResources(udcDayOfMonth, "udcDayOfMonth"); + udcDayOfMonth.Maximum = new decimal(new int[] { 31, 0, 0, 0 }); + udcDayOfMonth.Minimum = new decimal(new int[] { 1, 0, 0, 0 }); + udcDayOfMonth.Name = "udcDayOfMonth"; + udcDayOfMonth.Value = new decimal(new int[] { 1, 0, 0, 0 }); // // udcMinimumYear // - resources.ApplyResources(this.udcMinimumYear, "udcMinimumYear"); - this.udcMinimumYear.Maximum = new decimal(new int[] { - 9999, - 0, - 0, - 0}); - this.udcMinimumYear.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.udcMinimumYear.Name = "udcMinimumYear"; - this.udcMinimumYear.Value = new decimal(new int[] { - 1, - 0, - 0, - 0}); + resources.ApplyResources(udcMinimumYear, "udcMinimumYear"); + udcMinimumYear.Maximum = new decimal(new int[] { 9999, 0, 0, 0 }); + udcMinimumYear.Minimum = new decimal(new int[] { 1, 0, 0, 0 }); + udcMinimumYear.Name = "udcMinimumYear"; + udcMinimumYear.Value = new decimal(new int[] { 1, 0, 0, 0 }); // // label7 // - resources.ApplyResources(this.label7, "label7"); - this.label7.Name = "label7"; + resources.ApplyResources(label7, "label7"); + label7.Name = "label7"; // // udcMaximumYear // - resources.ApplyResources(this.udcMaximumYear, "udcMaximumYear"); - this.udcMaximumYear.Maximum = new decimal(new int[] { - 9999, - 0, - 0, - 0}); - this.udcMaximumYear.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.udcMaximumYear.Name = "udcMaximumYear"; - this.udcMaximumYear.Value = new decimal(new int[] { - 1, - 0, - 0, - 0}); + resources.ApplyResources(udcMaximumYear, "udcMaximumYear"); + udcMaximumYear.Maximum = new decimal(new int[] { 9999, 0, 0, 0 }); + udcMaximumYear.Minimum = new decimal(new int[] { 1, 0, 0, 0 }); + udcMaximumYear.Name = "udcMaximumYear"; + udcMaximumYear.Value = new decimal(new int[] { 1, 0, 0, 0 }); // // label8 // - resources.ApplyResources(this.label8, "label8"); - this.label8.Name = "label8"; + resources.ApplyResources(label8, "label8"); + label8.Name = "label8"; // // HolidayPropertiesDlg // - this.AcceptButton = this.btnOK; + this.AcceptButton = btnOK; resources.ApplyResources(this, "$this"); - this.CancelButton = this.btnCancel; - this.Controls.Add(this.udcMaximumYear); - this.Controls.Add(this.label8); - this.Controls.Add(this.udcMinimumYear); - this.Controls.Add(this.label7); - this.Controls.Add(this.udcDayOfMonth); - this.Controls.Add(this.udcOffset); - this.Controls.Add(this.chkAdjustDate); - this.Controls.Add(this.cboMonth); - this.Controls.Add(this.label6); - this.Controls.Add(this.cboDayOfWeek); - this.Controls.Add(this.label5); - this.Controls.Add(this.cboOccurrence); - this.Controls.Add(this.txtDescription); - this.Controls.Add(this.label4); - this.Controls.Add(this.label3); - this.Controls.Add(this.rbFixed); - this.Controls.Add(this.label2); - this.Controls.Add(this.label1); - this.Controls.Add(this.btnCancel); - this.Controls.Add(this.btnOK); - this.Controls.Add(this.rbFloating); + this.CancelButton = btnCancel; + this.Controls.Add(udcMaximumYear); + this.Controls.Add(label8); + this.Controls.Add(udcMinimumYear); + this.Controls.Add(label7); + this.Controls.Add(udcDayOfMonth); + this.Controls.Add(udcOffset); + this.Controls.Add(chkAdjustDate); + this.Controls.Add(cboMonth); + this.Controls.Add(label6); + this.Controls.Add(cboDayOfWeek); + this.Controls.Add(label5); + this.Controls.Add(cboOccurrence); + this.Controls.Add(txtDescription); + this.Controls.Add(label4); + this.Controls.Add(label3); + this.Controls.Add(rbFixed); + this.Controls.Add(label2); + this.Controls.Add(label1); + this.Controls.Add(btnCancel); + this.Controls.Add(btnOK); + this.Controls.Add(rbFloating); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "HolidayPropertiesDlg"; this.ShowInTaskbar = false; - this.Closing += new System.ComponentModel.CancelEventHandler(this.HolidayPropertiesDlg_Closing); - this.Load += new System.EventHandler(this.HolidayPropertiesDlg_Load); - ((System.ComponentModel.ISupportInitialize)(this.epErrors)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.udcOffset)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.udcDayOfMonth)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.udcMinimumYear)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.udcMaximumYear)).EndInit(); + this.Closing += this.HolidayPropertiesDlg_Closing; + ((System.ComponentModel.ISupportInitialize)epErrors).EndInit(); + ((System.ComponentModel.ISupportInitialize)udcOffset).EndInit(); + ((System.ComponentModel.ISupportInitialize)udcDayOfMonth).EndInit(); + ((System.ComponentModel.ISupportInitialize)udcMinimumYear).EndInit(); + ((System.ComponentModel.ISupportInitialize)udcMaximumYear).EndInit(); this.ResumeLayout(false); this.PerformLayout(); - } #endregion diff --git a/Source/EWSPDIWinForms/HolidayPropertiesDlg.cs b/Source/EWSPDIWinForms/HolidayPropertiesDlg.cs index 50e7b43..2e72914 100644 --- a/Source/EWSPDIWinForms/HolidayPropertiesDlg.cs +++ b/Source/EWSPDIWinForms/HolidayPropertiesDlg.cs @@ -2,8 +2,8 @@ // System : EWSoftware.PDI Windows Forms Controls // File : HolidayPropertiesDlg.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/23/2021 -// Note : Copyright 2003-2021, Eric Woodruff, All rights reserved +// Updated : 01/02/2025 +// Note : Copyright 2003-2025, Eric Woodruff, All rights reserved // // This is used to add or edit holiday object information // @@ -30,7 +30,7 @@ public partial class HolidayPropertiesDlg : System.Windows.Forms.Form #region Private data members //===================================================================== - private Holiday holiday; + private Holiday holiday = null!; #endregion @@ -89,8 +89,6 @@ public HolidayPropertiesDlg() { InitializeComponent(); - holiday = null; - cboMonth.DisplayMember = "Display"; cboMonth.ValueMember = "Value"; cboMonth.DataSource = RecurOptsDataSource.MonthsOfYear; @@ -102,21 +100,14 @@ public HolidayPropertiesDlg() cboDayOfWeek.DisplayMember = "Display"; cboDayOfWeek.ValueMember = "Value"; cboDayOfWeek.DataSource = RecurOptsDataSource.DayOfWeek; - } + + this.HolidayInfo = new FixedHoliday(1, 1, true, String.Empty); + } #endregion #region Event handlers //===================================================================== - /// - /// If loaded without setting a holiday object, create a new one - /// - private void HolidayPropertiesDlg_Load(object sender, System.EventArgs e) - { - if(holiday == null) - this.HolidayInfo = new FixedHoliday(1, 1, true, String.Empty); - } - /// /// Perform validation and store the changes /// @@ -144,7 +135,7 @@ private void HolidayPropertiesDlg_Closing(object sender, System.ComponentModel.C } // Leap years aren't accepted so always use a non-leap year to check the date - if(rbFixed.Checked && udcDayOfMonth.Value > DateTime.DaysInMonth(2003, (int)cboMonth.SelectedValue)) + if(rbFixed.Checked && udcDayOfMonth.Value > DateTime.DaysInMonth(2003, (int)cboMonth.SelectedValue!)) { epErrors.SetError(udcDayOfMonth, LR.GetString("EditHAEBadDayOfMonth")); e.Cancel = true; @@ -155,23 +146,23 @@ private void HolidayPropertiesDlg_Closing(object sender, System.ComponentModel.C { if(!rbFixed.Checked) { - FloatingHoliday fl = new FloatingHoliday(); + FloatingHoliday fl = new(); holiday = fl; - fl.Occurrence = (DayOccurrence)cboOccurrence.SelectedValue; - fl.Weekday = (System.DayOfWeek)cboDayOfWeek.SelectedValue; + fl.Occurrence = (DayOccurrence)cboOccurrence.SelectedValue!; + fl.Weekday = (DayOfWeek)cboDayOfWeek.SelectedValue!; fl.Offset = (int)udcOffset.Value; } else { - FixedHoliday fx = new FixedHoliday(); + FixedHoliday fx = new(); holiday = fx; fx.AdjustFixedDate = chkAdjustDate.Checked; fx.Day = (int)udcDayOfMonth.Value; } - holiday.Month = (int)cboMonth.SelectedValue; + holiday.Month = (int)cboMonth.SelectedValue!; holiday.Description = txtDescription.Text; holiday.MinimumYear = (int)udcMinimumYear.Value; holiday.MaximumYear = (int)udcMaximumYear.Value; diff --git a/Source/EWSPDIWinForms/HolidayPropertiesDlg.resx b/Source/EWSPDIWinForms/HolidayPropertiesDlg.resx index 70d1c0b..bae5ed0 100644 --- a/Source/EWSPDIWinForms/HolidayPropertiesDlg.resx +++ b/Source/EWSPDIWinForms/HolidayPropertiesDlg.resx @@ -1,17 +1,17 @@ - @@ -117,16 +117,16 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + NoControl - 12, 371 + 12, 385 - 117, 40 + 103, 42 @@ -139,7 +139,7 @@ btnOK - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Button, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -151,10 +151,10 @@ NoControl - 480, 371 + 448, 385 - 118, 40 + 103, 42 20 @@ -166,7 +166,7 @@ btnCancel - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Button, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -178,10 +178,10 @@ NoControl - 13, 19 + 38, 20 - 120, 29 + 105, 31 0 @@ -196,7 +196,7 @@ label1 - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Label, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -205,10 +205,10 @@ 17 - 139, 20 + 149, 21 - 437, 26 + 382, 27 1 @@ -217,7 +217,7 @@ txtDescription - System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.TextBox, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -229,10 +229,10 @@ NoControl - 55, 60 + 75, 63 - 78, 29 + 68, 31 2 @@ -247,7 +247,7 @@ label2 - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Label, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -259,10 +259,10 @@ NoControl - 25, 148 + 49, 156 - 195, 31 + 170, 32 8 @@ -274,7 +274,7 @@ rbFloating - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.RadioButton, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -286,10 +286,10 @@ NoControl - 25, 268 + 49, 282 - 179, 30 + 156, 32 15 @@ -301,7 +301,7 @@ rbFixed - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.RadioButton, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -313,10 +313,10 @@ NoControl - 214, 269 + 214, 283 - 141, 29 + 124, 31 16 @@ -331,7 +331,7 @@ label3 - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Label, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -343,10 +343,10 @@ NoControl - 281, 228 + 273, 240 - 74, 30 + 65, 32 13 @@ -361,7 +361,7 @@ label4 - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Label, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -373,13 +373,13 @@ 20 - 361, 150 + 343, 158 12 - 107, 28 + 94, 28 10 @@ -388,7 +388,7 @@ cboOccurrence - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.ComboBox, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -400,10 +400,10 @@ NoControl - 230, 149 + 228, 157 - 125, 29 + 110, 30 9 @@ -418,7 +418,7 @@ label5 - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Label, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -430,10 +430,10 @@ NoControl - 193, 189 + 196, 199 - 162, 29 + 142, 30 11 @@ -448,7 +448,7 @@ label6 - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Label, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -460,13 +460,13 @@ 20 - 361, 190 + 343, 200 12 - 160, 28 + 140, 28 12 @@ -475,7 +475,7 @@ cboDayOfWeek - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.ComboBox, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -487,13 +487,13 @@ 20 - 139, 61 + 149, 64 12 - 138, 28 + 120, 28 3 @@ -502,7 +502,7 @@ cboMonth - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.ComboBox, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -517,16 +517,16 @@ True - 8, 19 + 7, 20 - 610, 423 + 563, 439 - 361, 104 + 343, 109 - 75, 26 + 66, 27 7 @@ -538,7 +538,7 @@ udcMaximumYear - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.NumericUpDown, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -550,10 +550,10 @@ NoControl - 226, 101 + 225, 106 - 129, 30 + 113, 32 6 @@ -568,7 +568,7 @@ label8 - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Label, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -577,10 +577,10 @@ 1 - 139, 104 + 149, 109 - 75, 26 + 65, 27 5 @@ -592,7 +592,7 @@ udcMinimumYear - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.NumericUpDown, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -604,10 +604,10 @@ NoControl - 4, 101 + 31, 106 - 129, 30 + 112, 32 4 @@ -622,7 +622,7 @@ label7 - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Label, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -631,10 +631,10 @@ 3 - 361, 271 + 343, 285 - 65, 26 + 57, 27 17 @@ -646,7 +646,7 @@ udcDayOfMonth - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.NumericUpDown, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -655,10 +655,10 @@ 4 - 361, 231 + 343, 243 - 65, 26 + 57, 27 14 @@ -670,7 +670,7 @@ udcOffset - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.NumericUpDown, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -682,10 +682,10 @@ NoControl - 139, 317 + 149, 334 - 352, 30 + 308, 31 18 @@ -697,7 +697,7 @@ chkAdjustDate - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.CheckBox, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -715,12 +715,12 @@ epErrors - System.Windows.Forms.ErrorProvider, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.ErrorProvider, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 HolidayPropertiesDlg - System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Form, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 \ No newline at end of file diff --git a/Source/EWSPDIWinForms/LocalizedResources.cs b/Source/EWSPDIWinForms/LocalizedResources.cs index cccde58..b78aed9 100644 --- a/Source/EWSPDIWinForms/LocalizedResources.cs +++ b/Source/EWSPDIWinForms/LocalizedResources.cs @@ -2,9 +2,8 @@ // System : EWSoftware.PDI Windows Forms Controls // File : LocalizedResources.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 11/22/2018 -// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains some internal classes used to manage the localized resources for the assembly // @@ -23,7 +22,7 @@ using System.Globalization; using System.Resources; -namespace EWSoftware.PDI +namespace EWSoftware.PDI.Windows.Forms { /// /// This class is used to load resources for the assembly @@ -38,10 +37,10 @@ internal static class LR private const string ResourcesKey = "PDIWinForms"; // The resource manager - private static ResourceManager rm; + private static ResourceManager rm = null!; // This is a helper object used to quickly lock the class when creating the resource manager - private static readonly object syncRoot = new Object(); + private static readonly object syncRoot = new(); #endregion @@ -84,12 +83,7 @@ private static ResourceManager Resources /// "[?:<key>]" if not found. internal static string GetString(string name) { - string s = Resources.GetString(name, null); - - if(s == null) - s = $"[?:{name}]"; - - return s; + return Resources.GetString(name, null) ?? $"[?:{name}]"; } /// diff --git a/Source/EWSPDIWinForms/MonthlyPattern.cs b/Source/EWSPDIWinForms/MonthlyPattern.cs index 60bc765..6de9368 100644 --- a/Source/EWSPDIWinForms/MonthlyPattern.cs +++ b/Source/EWSPDIWinForms/MonthlyPattern.cs @@ -2,9 +2,8 @@ // System : EWSoftware.PDI Windows Forms Controls // File : MonthlyPattern.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/21/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains one of several user controls that are combined to allow the editing of various recurrence // parameters. This one is used to specify the settings for a monthly recurrence pattern. @@ -21,7 +20,6 @@ using System; using System.ComponentModel; -using System.Windows.Forms; namespace EWSoftware.PDI.Windows.Forms { @@ -77,28 +75,28 @@ public void GetValues(Recurrence recurrence) recurrence.Interval = (int)udcDOWMonths.Value; // If it's a single day, use ByDay. If it's a combination, use ByDay with BySetPos - rd = (DaysOfWeek)cboDOW.SelectedValue; - instance = ((DayOccurrence)cboOccurrence.SelectedValue == DayOccurrence.Last) ? -1 : + rd = (DaysOfWeek)cboDOW.SelectedValue!; + instance = ((DayOccurrence)cboOccurrence.SelectedValue! == DayOccurrence.Last) ? -1 : (int)cboOccurrence.SelectedValue; switch(rd) { case DaysOfWeek.EveryDay: recurrence.BySetPos.Add(instance); - recurrence.ByDay.AddRange(new DayOfWeek[] { DayOfWeek.Sunday, DayOfWeek.Monday, + recurrence.ByDay.AddRange([ DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday, - DayOfWeek.Saturday }); + DayOfWeek.Saturday ]); break; case DaysOfWeek.Weekdays: recurrence.BySetPos.Add(instance); - recurrence.ByDay.AddRange(new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Tuesday, - DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday }); + recurrence.ByDay.AddRange([ DayOfWeek.Monday, DayOfWeek.Tuesday, + DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday ]); break; case DaysOfWeek.Weekends: recurrence.BySetPos.Add(instance); - recurrence.ByDay.AddRange(new DayOfWeek[] { DayOfWeek.Sunday, DayOfWeek.Saturday }); + recurrence.ByDay.AddRange([DayOfWeek.Sunday, DayOfWeek.Saturday]); break; default: @@ -111,29 +109,29 @@ public void GetValues(Recurrence recurrence) /// /// This is called to set the values for the controls based on the current recurrence settings /// - /// The recurrence object from which to get the settings - public void SetValues(Recurrence rrecurrence) + /// The recurrence object from which to get the settings + public void SetValues(Recurrence recurrence) { DaysOfWeek rd = DaysOfWeek.None; rbDayXEveryYMonths.Checked = true; // Use default values if not a monthly frequency - if(rrecurrence.Frequency != RecurFrequency.Monthly) + if(recurrence.Frequency != RecurFrequency.Monthly) { udcDay.Value = udcMonths.Value = udcDOWMonths.Value = 1; cboOccurrence.SelectedIndex = cboDOW.SelectedIndex = 0; } else { - if(rrecurrence.ByDay.Count == 0) + if(recurrence.ByDay.Count == 0) { - if(rrecurrence.ByMonthDay.Count != 0) - udcDay.Value = rrecurrence.ByMonthDay[0]; + if(recurrence.ByMonthDay.Count != 0) + udcDay.Value = recurrence.ByMonthDay[0]; else - udcDay.Value = rrecurrence.StartDateTime.Day; + udcDay.Value = recurrence.StartDateTime.Day; - udcMonths.Value = (rrecurrence.Interval < 1000) ? rrecurrence.Interval : 999; + udcMonths.Value = (recurrence.Interval < 1000) ? recurrence.Interval : 999; cboOccurrence.SelectedIndex = cboDOW.SelectedIndex = 0; udcDOWMonths.Value = 1; @@ -143,28 +141,31 @@ public void SetValues(Recurrence rrecurrence) rbDayOfWeek.Checked = true; udcDay.Value = udcMonths.Value = 1; - udcDOWMonths.Value = (rrecurrence.Interval < 1000) ? rrecurrence.Interval : 999; + udcDOWMonths.Value = (recurrence.Interval < 1000) ? recurrence.Interval : 999; // If it's a single day, use ByDay. If it's a combination, use ByDay with BySetPos. - if(rrecurrence.ByDay.Count == 1) + if(recurrence.ByDay.Count == 1) { - cboOccurrence.SelectedValue = (rrecurrence.ByDay[0].Instance < 1 || - rrecurrence.ByDay[0].Instance > 4) ? DayOccurrence.Last : - (DayOccurrence)rrecurrence.ByDay[0].Instance; + cboOccurrence.SelectedValue = (recurrence.ByDay[0].Instance < 1 || + recurrence.ByDay[0].Instance > 4) ? DayOccurrence.Last : + (DayOccurrence)recurrence.ByDay[0].Instance; - cboDOW.SelectedValue = DateUtils.ToDaysOfWeek(rrecurrence.ByDay[0].DayOfWeek); + cboDOW.SelectedValue = DateUtils.ToDaysOfWeek(recurrence.ByDay[0].DayOfWeek); } else { - if(rrecurrence.BySetPos.Count == 0) + if(recurrence.BySetPos.Count == 0) cboOccurrence.SelectedIndex = 0; else - cboOccurrence.SelectedValue = (rrecurrence.BySetPos[0] < 1 || - rrecurrence.BySetPos[0] > 4) ? DayOccurrence.Last : - (DayOccurrence)rrecurrence.BySetPos[0]; + { + cboOccurrence.SelectedValue = (recurrence.BySetPos[0] < 1 || + recurrence.BySetPos[0] > 4) ? DayOccurrence.Last : + (DayOccurrence)recurrence.BySetPos[0]; + } // Figure out days used - foreach(DayInstance di in rrecurrence.ByDay) + foreach(DayInstance di in recurrence.ByDay) + { switch(di.DayOfWeek) { case DayOfWeek.Sunday: @@ -195,11 +196,14 @@ public void SetValues(Recurrence rrecurrence) rd |= DaysOfWeek.Saturday; break; } + } // If not EveryDay, Weekdays, or Weekends, force it to a single day of the week if(rd == DaysOfWeek.None || (rd != DaysOfWeek.EveryDay && rd != DaysOfWeek.Weekdays && rd != DaysOfWeek.Weekends)) + { rd = DateUtils.ToDaysOfWeek(DateUtils.ToDayOfWeek(rd)); + } cboDOW.SelectedValue = rd; } @@ -214,12 +218,10 @@ public void SetValues(Recurrence rrecurrence) /// /// Enable or disable the controls based on the selection /// - private void Monthly_CheckedChanged(object sender, System.EventArgs e) + private void Monthly_CheckedChanged(object sender, EventArgs e) { - RadioButton r = (sender as RadioButton); - - udcDay.Enabled = udcMonths.Enabled = (r == rbDayXEveryYMonths); - cboOccurrence.Enabled = cboDOW.Enabled = udcDOWMonths.Enabled = (r == rbDayOfWeek); + udcDay.Enabled = udcMonths.Enabled = sender == rbDayXEveryYMonths; + cboOccurrence.Enabled = cboDOW.Enabled = udcDOWMonths.Enabled = sender == rbDayOfWeek; } #endregion } diff --git a/Source/EWSPDIWinForms/PDIWinForms.Designer.cs b/Source/EWSPDIWinForms/PDIWinForms.Designer.cs deleted file mode 100644 index 1032fe6..0000000 --- a/Source/EWSPDIWinForms/PDIWinForms.Designer.cs +++ /dev/null @@ -1,245 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace EWSoftware.PDI.Windows.Forms { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class PDIWinForms { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal PDIWinForms() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("EWSoftware.PDI.Windows.Forms.PDIWinForms", typeof(PDIWinForms).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to day(s). - /// - internal static string APDaily { - get { - return ResourceManager.GetString("APDaily", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to hour(s). - /// - internal static string APHourly { - get { - return ResourceManager.GetString("APHourly", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to minute(s). - /// - internal static string APMinutely { - get { - return ResourceManager.GetString("APMinutely", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to month(s). - /// - internal static string APMonthly { - get { - return ResourceManager.GetString("APMonthly", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to second(s). - /// - internal static string APSecondly { - get { - return ResourceManager.GetString("APSecondly", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to week(s). - /// - internal static string APWeekly { - get { - return ResourceManager.GetString("APWeekly", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to year(s). - /// - internal static string APYearly { - get { - return ResourceManager.GetString("APYearly", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} of {1}. - /// - internal static string BCCountInd { - get { - return ResourceManager.GetString("BCCountInd", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to A valid day for the selected month must be specified. - /// - internal static string EditHAEBadDayOfMonth { - get { - return ResourceManager.GetString("EditHAEBadDayOfMonth", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Description cannot be blank. - /// - internal static string EditHAEBlankDesc { - get { - return ResourceManager.GetString("EditHAEBlankDesc", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Please select a holiday first. - /// - internal static string EditHMSelectHoliday { - get { - return ResourceManager.GetString("EditHMSelectHoliday", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Holiday instance must not be null. - /// - internal static string ExHAEHolidayIsNull { - get { - return ResourceManager.GetString("ExHAEHolidayIsNull", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The recurrence object cannot be null. - /// - internal static string ExRPRecurrenceIsNull { - get { - return ResourceManager.GetString("ExRPRecurrenceIsNull", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error Loading Holidays. - /// - internal static string HMErrorLoading { - get { - return ResourceManager.GetString("HMErrorLoading", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error Saving Holidays. - /// - internal static string HMErrorSaving { - get { - return ResourceManager.GetString("HMErrorSaving", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to XML files (*.xml)|*.xml|All files (*.*)|*.*. - /// - internal static string HMFileDlgFilter { - get { - return ResourceManager.GetString("HMFileDlgFilter", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to load holidays: - ///{0}. - /// - internal static string HMLoadError { - get { - return ResourceManager.GetString("HMLoadError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Load Holidays From XML File. - /// - internal static string HMLoadTitle { - get { - return ResourceManager.GetString("HMLoadTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to save holidays: - ///{0}. - /// - internal static string HMSaveError { - get { - return ResourceManager.GetString("HMSaveError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Save Holidays To XML File. - /// - internal static string HMSaveTitle { - get { - return ResourceManager.GetString("HMSaveTitle", resourceCulture); - } - } - } -} diff --git a/Source/EWSPDIWinForms/Properties/AssemblyInfo.cs b/Source/EWSPDIWinForms/Properties/AssemblyInfo.cs index f452d41..bf13251 100644 --- a/Source/EWSPDIWinForms/Properties/AssemblyInfo.cs +++ b/Source/EWSPDIWinForms/Properties/AssemblyInfo.cs @@ -22,7 +22,7 @@ // General assembly information [assembly: AssemblyTitle("EWSoftware.PDI Windows Forms Controls")] -#if NET6_0_OR_GREATER +#if NET8_0_OR_GREATER [assembly: System.Runtime.Versioning.SupportedOSPlatform("windows")] #endif diff --git a/Source/EWSPDIWinForms/ReadMe.txt b/Source/EWSPDIWinForms/ReadMe.md similarity index 78% rename from Source/EWSPDIWinForms/ReadMe.txt rename to Source/EWSPDIWinForms/ReadMe.md index 2bb7918..88f0967 100644 --- a/Source/EWSPDIWinForms/ReadMe.txt +++ b/Source/EWSPDIWinForms/ReadMe.md @@ -1,5 +1,4 @@ -EWSoftware.PDI.Windows.Forms Control Library --------------------------------------------- +# EWSoftware.PDI.Windows.Forms Control Library This library contains some Windows Forms controls that can be used to edit holiday calculation settings and to edit recurrence settings. diff --git a/Source/EWSPDIWinForms/RecurrencePattern.bmp b/Source/EWSPDIWinForms/RecurrencePattern.bmp deleted file mode 100644 index e257305ef1ccfb838f6876816e2d8b8aaeda1c7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcmYLBxedfH4ATJt;_}AG9O<)5s-sGE_AHsgQ>FEhwu8_j^-%JD+&1uI+Q{$Z$ChqH z*CCHLIywxC7>UZ#YOTyNS`TYY70IU&<(j|?9jt(-Qc4DbBs@_HaI$sF9;z*IIfDl< U`7zg-{khRtH~dX2r (dtpEndDate.Width == 235); + get => dtpEndDate.Width == 235; set { // Set the date/time pattern based on the current culture @@ -249,14 +252,14 @@ public RecurrencePattern() /// This is thrown if the passed recurrence object is null public void GetRecurrence(Recurrence recurrence) { - Recurrence r = new Recurrence(); + Recurrence r = new(); if(recurrence == null) throw new ArgumentNullException(nameof(recurrence), LR.GetString("ExRPRecurrenceIsNull")); // Get the basic stuff r.Reset(); - r.WeekStart = (DayOfWeek)cboWeekStartDay.SelectedValue; + r.WeekStart = (DayOfWeek)cboWeekStartDay.SelectedValue!; r.CanOccurOnHoliday = chkHolidays.Checked; r.Frequency = rbYearly.Checked ? RecurFrequency.Yearly : @@ -269,35 +272,51 @@ public void GetRecurrence(Recurrence recurrence) if(rbEndAfter.Checked) r.MaximumOccurrences = (int)udcOccurrences.Value; else + { if(rbEndByDate.Checked) + { if(this.ShowEndTime) r.RecurUntil = dtpEndDate.Value; else r.RecurUntil = dtpEndDate.Value.Date; + } + } // Get the frequency-specific stuff if(chkAdvanced.Checked) ucAdvanced.GetValues(r); else + { if(rbYearly.Checked) ucYearly.GetValues(r); else + { if(rbMonthly.Checked) ucMonthly.GetValues(r); else + { if(rbWeekly.Checked) ucWeekly.GetValues(r); else + { if(rbDaily.Checked) ucDaily.GetValues(r); else + { if(rbHourly.Checked) ucHourly.GetValues(r); else + { if(rbMinutely.Checked) ucMinutely.GetValues(r); else ucSecondly.GetValues(r); + } + } + } + } + } + } recurrence.Parse(r.ToString()); } @@ -307,9 +326,9 @@ public void GetRecurrence(Recurrence recurrence) /// /// The recurrence from which to get the settings. If null, it uses a default /// daily recurrence pattern. - public void SetRecurrence(Recurrence recurrence) + public void SetRecurrence(Recurrence? recurrence) { - Recurrence r = new Recurrence(); + Recurrence r = new(); if(recurrence == null) { @@ -321,6 +340,7 @@ public void SetRecurrence(Recurrence recurrence) // If the given pattern is not available, set it to the next best pattern if(maxPattern < r.Frequency) + { switch(maxPattern) { case RecurFrequency.Yearly: @@ -349,6 +369,7 @@ public void SetRecurrence(Recurrence recurrence) r.Frequency = RecurFrequency.Minutely; break; } + } switch(r.Frequency) { @@ -397,6 +418,7 @@ public void SetRecurrence(Recurrence recurrence) udcOccurrences.Value = (r.MaximumOccurrences < 1000) ? r.MaximumOccurrences : 999; } else + { if(r.RecurUntil == DateTime.MaxValue) rbNeverEnds.Checked = true; else @@ -404,6 +426,7 @@ public void SetRecurrence(Recurrence recurrence) rbEndByDate.Checked = true; dtpEndDate.Value = r.RecurUntil; } + } // Set parameters in the sub-controls. Set them all so that when the Advanced pane is hidden or // shown, it keeps them consistent when first opened. @@ -433,10 +456,8 @@ public void SetRecurrence(Recurrence recurrence) /// /// The sender of the event /// The event arguments - private void Pattern_CheckedChanged(object sender, System.EventArgs e) + private void Pattern_CheckedChanged(object sender, EventArgs e) { - RadioButton r = sender as RadioButton; - ucAdvanced.SetFrequency(rbYearly.Checked ? RecurFrequency.Yearly : rbMonthly.Checked ? RecurFrequency.Monthly : rbWeekly.Checked ? RecurFrequency.Weekly : @@ -444,13 +465,13 @@ private void Pattern_CheckedChanged(object sender, System.EventArgs e) rbHourly.Checked ? RecurFrequency.Hourly : rbMinutely.Checked ? RecurFrequency.Minutely : RecurFrequency.Secondly); - ucYearly.Visible = (r == rbYearly); - ucMonthly.Visible = (r == rbMonthly); - ucWeekly.Visible = (r == rbWeekly); - ucDaily.Visible = (r == rbDaily); - ucHourly.Visible = (r == rbHourly); - ucMinutely.Visible = (r == rbMinutely); - ucSecondly.Visible = (r == rbSecondly); + ucYearly.Visible = rbYearly.Checked; + ucMonthly.Visible = rbMonthly.Checked; + ucWeekly.Visible = rbWeekly.Checked; + ucDaily.Visible = rbDaily.Checked; + ucHourly.Visible = rbHourly.Checked; + ucMinutely.Visible = rbMinutely.Checked; + ucSecondly.Visible = rbSecondly.Checked; } /// @@ -458,12 +479,10 @@ private void Pattern_CheckedChanged(object sender, System.EventArgs e) /// /// The sender of the event /// The event arguments - private void Range_CheckedChanged(object sender, System.EventArgs e) + private void Range_CheckedChanged(object sender, EventArgs e) { - RadioButton r = sender as RadioButton; - - udcOccurrences.Enabled = (r == rbEndAfter); - dtpEndDate.Enabled = (r == rbEndByDate); + udcOccurrences.Enabled = sender == rbEndAfter; + dtpEndDate.Enabled = sender == rbEndByDate; } /// @@ -471,9 +490,9 @@ private void Range_CheckedChanged(object sender, System.EventArgs e) /// /// The sender of the event /// The event arguments - private void chkAdvanced_CheckedChanged(object sender, System.EventArgs e) + private void chkAdvanced_CheckedChanged(object sender, EventArgs e) { - Recurrence r = new Recurrence(); + Recurrence r = new(); // Don't copy settings if the current context doesn't warrant it. Just change the state of the // panels. @@ -514,22 +533,32 @@ private void chkAdvanced_CheckedChanged(object sender, System.EventArgs e) if(rbYearly.Checked) ucYearly.GetValues(r); else + { if(rbMonthly.Checked) ucMonthly.GetValues(r); else + { if(rbWeekly.Checked) ucWeekly.GetValues(r); else + { if(rbDaily.Checked) ucDaily.GetValues(r); else + { if(rbHourly.Checked) ucHourly.GetValues(r); else + { if(rbMinutely.Checked) ucMinutely.GetValues(r); else ucSecondly.GetValues(r); + } + } + } + } + } ucAdvanced.SetValues(r); diff --git a/Source/EWSPDIWinForms/RecurrencePattern.png b/Source/EWSPDIWinForms/RecurrencePattern.png new file mode 100644 index 0000000000000000000000000000000000000000..6090bfa9b203fde694df434fd7ae8eb807d6e5a9 GIT binary patch literal 524 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|m0G|-oM~@yYU9vPJI7Cxj^VF$R@p19lS=nn=uep8u_VQ)R_wCyURJdWo z22)ehqM{-oJ4@lm86YK4666>B9~Ce>P>z)Z%5fHWL>4nJ@ErzW#^d=bQh8ZuQ0pzeUNHMZ9FalX# zKr9VqgM6vM$P5-|0@05M2Ej7GDR0T@mb*cn)WDh!N_ z4Hy?dOavp@3Xlx~Oh9v(z$$|*Er2YjE<*zYknGE=-z-ku%Bcb}lRaG=Lo|YO z`=j{|C~&Yaipp=f`}_X3gIU74-hYIVxJ^?$3F}Radv`{-!6)c`0*w3_cuF QssmZ=>FVdQ&MBb@0Pks(o&W#< literal 0 HcmV?d00001 diff --git a/Source/EWSPDIWinForms/RecurrencePropertiesDlg.Designer.cs b/Source/EWSPDIWinForms/RecurrencePropertiesDlg.Designer.cs index 1fa2c01..dde31d9 100644 --- a/Source/EWSPDIWinForms/RecurrencePropertiesDlg.Designer.cs +++ b/Source/EWSPDIWinForms/RecurrencePropertiesDlg.Designer.cs @@ -22,49 +22,48 @@ protected override void Dispose(bool disposing) #region Windows Form Designer generated code - /// - /// Required method for Designer support - do not modify the contents of this method with the code editor - /// - private void InitializeComponent() - { + /// + /// Required method for Designer support - do not modify the contents of this method with the code editor + /// + private void InitializeComponent() + { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RecurrencePropertiesDlg)); - this.rpRecurrence = new EWSoftware.PDI.Windows.Forms.RecurrencePattern(); - this.btnCancel = new System.Windows.Forms.Button(); - this.btnOK = new System.Windows.Forms.Button(); + rpRecurrence = new RecurrencePattern(); + btnCancel = new System.Windows.Forms.Button(); + btnOK = new System.Windows.Forms.Button(); this.SuspendLayout(); // // rpRecurrence // - resources.ApplyResources(this.rpRecurrence, "rpRecurrence"); - this.rpRecurrence.Name = "rpRecurrence"; - this.rpRecurrence.ShowEndTime = false; + resources.ApplyResources(rpRecurrence, "rpRecurrence"); + rpRecurrence.Name = "rpRecurrence"; + rpRecurrence.ShowEndTime = false; // // btnCancel // - resources.ApplyResources(this.btnCancel, "btnCancel"); - this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.btnCancel.Name = "btnCancel"; + resources.ApplyResources(btnCancel, "btnCancel"); + btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + btnCancel.Name = "btnCancel"; // // btnOK // - resources.ApplyResources(this.btnOK, "btnOK"); - this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; - this.btnOK.Name = "btnOK"; + resources.ApplyResources(btnOK, "btnOK"); + btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + btnOK.Name = "btnOK"; // // RecurrencePropertiesDlg // - this.AcceptButton = this.btnOK; + this.AcceptButton = btnOK; resources.ApplyResources(this, "$this"); - this.CancelButton = this.btnCancel; - this.Controls.Add(this.btnCancel); - this.Controls.Add(this.btnOK); - this.Controls.Add(this.rpRecurrence); + this.CancelButton = btnCancel; + this.Controls.Add(btnCancel); + this.Controls.Add(btnOK); + this.Controls.Add(rpRecurrence); this.MinimizeBox = false; this.Name = "RecurrencePropertiesDlg"; this.ShowInTaskbar = false; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show; this.ResumeLayout(false); - } #endregion diff --git a/Source/EWSPDIWinForms/RecurrencePropertiesDlg.resx b/Source/EWSPDIWinForms/RecurrencePropertiesDlg.resx index ab85b2b..2e876d7 100644 --- a/Source/EWSPDIWinForms/RecurrencePropertiesDlg.resx +++ b/Source/EWSPDIWinForms/RecurrencePropertiesDlg.resx @@ -1,17 +1,17 @@ - @@ -117,7 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + Top, Bottom, Left, Right @@ -126,7 +126,7 @@ 0, 0 - 730, 451 + 721, 492 @@ -136,7 +136,7 @@ rpRecurrence - EWSoftware.PDI.Windows.Forms.RecurrencePattern, EWSoftware.PDI.Windows.Forms, Version=2018.11.17.0, Culture=neutral, PublicKeyToken=69a3299ed3c63934 + EWSoftware.PDI.Windows.Forms.RecurrencePattern, EWSoftware.PDI.Windows.Forms, Culture=neutral, PublicKeyToken=69a3299ed3c63934 $this @@ -151,10 +151,10 @@ NoControl - 600, 458 + 608, 498 - 117, 41 + 102, 43 2 @@ -166,7 +166,7 @@ btnCancel - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Button, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -181,10 +181,10 @@ NoControl - 16, 458 + 12, 498 - 117, 41 + 102, 43 1 @@ -196,7 +196,7 @@ btnOK - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Button, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -208,10 +208,10 @@ True - 8, 19 + 7, 20 - 728, 514 + 722, 553 @@ -281,10 +281,10 @@ - 750, 900 + 740, 947 - 750, 570 + 740, 600 CenterScreen @@ -296,6 +296,6 @@ RecurrencePropertiesDlg - System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Form, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089 \ No newline at end of file diff --git a/Source/EWSPDIWinForms/YearlyPattern.cs b/Source/EWSPDIWinForms/YearlyPattern.cs index 4942854..0874cba 100644 --- a/Source/EWSPDIWinForms/YearlyPattern.cs +++ b/Source/EWSPDIWinForms/YearlyPattern.cs @@ -2,9 +2,8 @@ // System : EWSoftware.PDI Windows Forms Controls // File : YearlyPattern.cs // Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 10/21/2014 -// Note : Copyright 2004-2014, Eric Woodruff, All rights reserved -// Compiler: Microsoft Visual C# +// Updated : 01/02/2025 +// Note : Copyright 2004-2025, Eric Woodruff, All rights reserved // // This file contains one of several user controls that are combined to allow the editing of various recurrence // parameters. This one is used to specify the settings for a yearly recurrence pattern. @@ -78,37 +77,37 @@ public void GetValues(Recurrence recurrence) if(rbDayXEveryYYears.Checked) { recurrence.Interval = (int)udcYears.Value; - recurrence.ByMonth.Add((int)cboMonth.SelectedValue); + recurrence.ByMonth.Add((int)cboMonth.SelectedValue!); recurrence.ByMonthDay.Add((int)udcDay.Value); } else { recurrence.Interval = (int)udcDOWYears.Value; - recurrence.ByMonth.Add((int)cboDOWMonth.SelectedValue); + recurrence.ByMonth.Add((int)cboDOWMonth.SelectedValue!); // If it's a single day, use ByDay. If it's a combination, use ByDay with BySetPos. - rd = (DaysOfWeek)cboDOW.SelectedValue; - instance = ((DayOccurrence)cboOccurrence.SelectedValue == DayOccurrence.Last) ? -1 : + rd = (DaysOfWeek)cboDOW.SelectedValue!; + instance = ((DayOccurrence)cboOccurrence.SelectedValue! == DayOccurrence.Last) ? -1 : (int)cboOccurrence.SelectedValue; switch(rd) { case DaysOfWeek.EveryDay: recurrence.BySetPos.Add(instance); - recurrence.ByDay.AddRange(new DayOfWeek[] { DayOfWeek.Sunday, DayOfWeek.Monday, + recurrence.ByDay.AddRange([ DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday, - DayOfWeek.Saturday }); + DayOfWeek.Saturday ]); break; case DaysOfWeek.Weekdays: recurrence.BySetPos.Add(instance); - recurrence.ByDay.AddRange(new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Tuesday, - DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday }); + recurrence.ByDay.AddRange([ DayOfWeek.Monday, DayOfWeek.Tuesday, + DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday ]); break; case DaysOfWeek.Weekends: recurrence.BySetPos.Add(instance); - recurrence.ByDay.AddRange(new DayOfWeek[] { DayOfWeek.Sunday, DayOfWeek.Saturday }); + recurrence.ByDay.AddRange([DayOfWeek.Sunday, DayOfWeek.Saturday]); break; default: @@ -187,6 +186,7 @@ public void SetValues(Recurrence recurrence) // Figure out days foreach(DayInstance di in recurrence.ByDay) + { switch(di.DayOfWeek) { case DayOfWeek.Sunday: @@ -217,11 +217,14 @@ public void SetValues(Recurrence recurrence) rd |= DaysOfWeek.Saturday; break; } + } // If not EveryDay, Weekdays, or Weekends, force it to a single day of the week if(rd == DaysOfWeek.None || (rd != DaysOfWeek.EveryDay && rd != DaysOfWeek.Weekdays && rd != DaysOfWeek.Weekends)) + { rd = DateUtils.ToDaysOfWeek(DateUtils.ToDayOfWeek(rd)); + } cboDOW.SelectedValue = rd; } @@ -240,10 +243,8 @@ public void SetValues(Recurrence recurrence) /// The event parameters private void Yearly_CheckedChanged(object sender, System.EventArgs e) { - RadioButton r = sender as RadioButton; - - cboMonth.Enabled = udcDay.Enabled = udcYears.Enabled = (r == rbDayXEveryYYears); - cboOccurrence.Enabled = cboDOW.Enabled = cboDOWMonth.Enabled = udcDOWYears.Enabled = (r == rbDayOfWeek); + cboMonth.Enabled = udcDay.Enabled = udcYears.Enabled = sender == rbDayXEveryYYears; + cboOccurrence.Enabled = cboDOW.Enabled = cboDOWMonth.Enabled = udcDOWYears.Enabled = sender == rbDayOfWeek; } /// diff --git a/Source/VBNetDemos/CalendarBrowser/AboutDlg.vb b/Source/VBNetDemos/CalendarBrowser/AboutDlg.vb index 9997862..5c55dee 100644 --- a/Source/VBNetDemos/CalendarBrowser/AboutDlg.vb +++ b/Source/VBNetDemos/CalendarBrowser/AboutDlg.vb @@ -20,6 +20,7 @@ ' Ignore Spelling: mailto Imports System.Reflection +Imports System.Security.Policy Public Partial Class AboutDlg Inherits System.Windows.Forms.Form @@ -35,28 +36,28 @@ Public Partial Class AboutDlg Dim asm As [Assembly] = [Assembly].GetEntryAssembly() Dim title As AssemblyTitleAttribute = DirectCast(AssemblyTitleAttribute.GetCustomAttribute(asm, GetType(AssemblyTitleAttribute)), AssemblyTitleAttribute) - Dim copyright As AssemblyCopyrightAttribute= DirectCast(AssemblyCopyrightAttribute.GetCustomAttribute(asm, - GetType(AssemblyCopyrightAttribute)), AssemblyCopyrightAttribute) - Dim desc As AssemblyDescriptionAttribute= DirectCast(AssemblyDescriptionAttribute.GetCustomAttribute(asm, - GetType(AssemblyDescriptionAttribute)), AssemblyDescriptionAttribute) +Dim copyright As AssemblyCopyrightAttribute= DirectCast(AssemblyCopyrightAttribute.GetCustomAttribute(asm, +GetType(AssemblyCopyrightAttribute)), AssemblyCopyrightAttribute) +Dim desc As AssemblyDescriptionAttribute= DirectCast(AssemblyDescriptionAttribute.GetCustomAttribute(asm, +GetType(AssemblyDescriptionAttribute)), AssemblyDescriptionAttribute) - ' Set the labels +' Set the labels lblName.Text = title.Title - lblDescription.Text = desc.Description - lblVersion.Text = "Version: " & Application.ProductVersion +lblDescription.Text = desc.Description +lblVersion.Text = "Version: " & Application.ProductVersion lblCopyright.Text = copyright.Copyright - ' Display components used by this assembly sorted by name - For Each an As AssemblyName In asm.GetReferencedAssemblies() - Dim lvi As ListViewItem= lvComponents.Items.Add(an.Name) - lvi.SubItems.Add(an.Version.ToString()) - Next +' Display components used by this assembly sorted by name +For Each an As AssemblyName In asm.GetReferencedAssemblies() +Dim lvi As ListViewItem= lvComponents.Items.Add(an.Name) +lvi.SubItems.Add(an.Version.ToString()) +Next lvComponents.Sorting = SortOrder.Ascending lvComponents.Sort() - ' Set e-mail link - lnkHelp.Links(0).LinkData = "mailto:" & lnkHelp.Text & "?Subject=EWSoftware CalendarBrowser Demo" +' Set e-mail link +lnkHelp.Links(0).LinkData = "mailto:" & lnkHelp.Text & "?Subject=EWSoftware CalendarBrowser Demo" End Sub Private Sub btnSysInfo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSysInfo.Click @@ -75,7 +76,11 @@ Public Partial Class AboutDlg ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles lnkHelp.LinkClicked Try ' Launch the e-mail URL, this will fail if user does not have an association for e-mail URLs - System.Diagnostics.Process.Start(DirectCast(e.Link.LinkData, String)) + Process.Start(New ProcessStartInfo With { + .FileName = DirectCast(e.Link.LinkData, String), + .UseShellExecute = True + }) + Catch ex As Exception MessageBox.Show("Unable to launch e-mail editor", "E-Mail Error", MessageBoxButtons.OK, MessageBoxIcon.Error) diff --git a/Source/VBNetDemos/CalendarBrowser/CalendarBrowser.vbproj b/Source/VBNetDemos/CalendarBrowser/CalendarBrowser.vbproj index 643a3b0..cd8f764 100644 --- a/Source/VBNetDemos/CalendarBrowser/CalendarBrowser.vbproj +++ b/Source/VBNetDemos/CalendarBrowser/CalendarBrowser.vbproj @@ -1,7 +1,7 @@  WinExe - net6.0-windows;net40 + net8.0-windows;net40 true False False diff --git a/Source/VBNetDemos/CalendarBrowser/My Project/AssemblyInfoShared.vb b/Source/VBNetDemos/CalendarBrowser/My Project/AssemblyInfoShared.vb index 3e09c96..c6defdc 100644 --- a/Source/VBNetDemos/CalendarBrowser/My Project/AssemblyInfoShared.vb +++ b/Source/VBNetDemos/CalendarBrowser/My Project/AssemblyInfoShared.vb @@ -2,8 +2,8 @@ ' System : EWSoftware PDI Demonstration Applications ' File : AssemblyInfo.cs ' Author : Eric Woodruff (Eric@EWoodruff.us) -' Updated : 01/02/2023 -' Note : Copyright 2004-2023, Eric Woodruff, All rights reserved +' Updated : 01/09/2025 +' Note : Copyright 2004-2025, Eric Woodruff, All rights reserved ' ' PDI library demos common assembly attributes ' @@ -50,5 +50,5 @@ Imports System.Runtime.InteropServices ' Day of release ' Revision (typically zero unless multiple releases are made on the same day) ' - - + + diff --git a/Source/VBNetDemos/CalendarBrowser/app.config b/Source/VBNetDemos/CalendarBrowser/app.config index 9659fad..bf23e96 100644 --- a/Source/VBNetDemos/CalendarBrowser/app.config +++ b/Source/VBNetDemos/CalendarBrowser/app.config @@ -20,9 +20,6 @@ - - - diff --git a/Source/VBNetDemos/PDIDatesTest/PDIDatesTest.vbproj b/Source/VBNetDemos/PDIDatesTest/PDIDatesTest.vbproj index e6ba988..9944119 100644 --- a/Source/VBNetDemos/PDIDatesTest/PDIDatesTest.vbproj +++ b/Source/VBNetDemos/PDIDatesTest/PDIDatesTest.vbproj @@ -2,7 +2,7 @@ Exe - net6.0;net40 + net8.0;net40 False False False diff --git a/Source/VBNetDemos/PDIParserTest/PDIParserTest.vbproj b/Source/VBNetDemos/PDIParserTest/PDIParserTest.vbproj index 30279bf..c36537a 100644 --- a/Source/VBNetDemos/PDIParserTest/PDIParserTest.vbproj +++ b/Source/VBNetDemos/PDIParserTest/PDIParserTest.vbproj @@ -2,7 +2,7 @@ Exe - net6.0;net40 + net8.0;net40 False False False diff --git a/Source/VBNetDemos/PDIWebDemoVB/Web.config b/Source/VBNetDemos/PDIWebDemoVB/Web.config index 87a8909..1aaf96e 100644 --- a/Source/VBNetDemos/PDIWebDemoVB/Web.config +++ b/Source/VBNetDemos/PDIWebDemoVB/Web.config @@ -29,7 +29,7 @@ - + diff --git a/Source/VBNetDemos/PDIWinFormsTest/AboutDlg.vb b/Source/VBNetDemos/PDIWinFormsTest/AboutDlg.vb index 1760a0e..fa739ba 100644 --- a/Source/VBNetDemos/PDIWinFormsTest/AboutDlg.vb +++ b/Source/VBNetDemos/PDIWinFormsTest/AboutDlg.vb @@ -75,7 +75,10 @@ Public Partial Class AboutDlg ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles lnkHelp.LinkClicked Try ' Launch the e-mail URL, this will fail if user does not have an association for e-mail URLs - System.Diagnostics.Process.Start(DirectCast(e.Link.LinkData, String)) + Process.Start(New ProcessStartInfo With { + .FileName = DirectCast(e.Link.LinkData, String), + .UseShellExecute = True + }) Catch ex As Exception MessageBox.Show("Unable to launch e-mail editor", "E-Mail Error", MessageBoxButtons.OK, MessageBoxIcon.Error) diff --git a/Source/VBNetDemos/PDIWinFormsTest/PDIWinFormsTest.vbproj b/Source/VBNetDemos/PDIWinFormsTest/PDIWinFormsTest.vbproj index bedf666..0ac52f3 100644 --- a/Source/VBNetDemos/PDIWinFormsTest/PDIWinFormsTest.vbproj +++ b/Source/VBNetDemos/PDIWinFormsTest/PDIWinFormsTest.vbproj @@ -1,7 +1,7 @@  WinExe - net6.0-windows;net40 + net8.0-windows;net40 true False False diff --git a/Source/VBNetDemos/RFC2445RecurTest/RFC2445RecurTest.vbproj b/Source/VBNetDemos/RFC2445RecurTest/RFC2445RecurTest.vbproj index f288751..7b01897 100644 --- a/Source/VBNetDemos/RFC2445RecurTest/RFC2445RecurTest.vbproj +++ b/Source/VBNetDemos/RFC2445RecurTest/RFC2445RecurTest.vbproj @@ -2,7 +2,7 @@ Exe - net6.0;net40 + net8.0;net40 False False False diff --git a/Source/VBNetDemos/vCardBrowser/AboutDlg.vb b/Source/VBNetDemos/vCardBrowser/AboutDlg.vb index 7b2808c..58ef17b 100644 --- a/Source/VBNetDemos/vCardBrowser/AboutDlg.vb +++ b/Source/VBNetDemos/vCardBrowser/AboutDlg.vb @@ -75,7 +75,11 @@ Public Partial Class AboutDlg ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles lnkHelp.LinkClicked Try ' Launch the e-mail URL, this will fail if user does not have an association for e-mail URLs - System.Diagnostics.Process.Start(DirectCast(e.Link.LinkData, String)) + Process.Start(New ProcessStartInfo With { + .FileName = DirectCast(e.Link.LinkData, String), + .UseShellExecute = True + }) + Catch ex As Exception MessageBox.Show("Unable to launch e-mail editor", "E-Mail Error", MessageBoxButtons.OK, MessageBoxIcon.Error) diff --git a/Source/VBNetDemos/vCardBrowser/AddressControl.vb b/Source/VBNetDemos/vCardBrowser/AddressControl.vb index 0cc361f..889dd15 100644 --- a/Source/VBNetDemos/vCardBrowser/AddressControl.vb +++ b/Source/VBNetDemos/vCardBrowser/AddressControl.vb @@ -209,7 +209,10 @@ Public Partial Class AddressControl End If Try - System.Diagnostics.Process.Start(sb.ToString()) + Process.Start(New ProcessStartInfo With { + .FileName = sb.ToString(), + .UseShellExecute = True + }) Catch ex As Exception MessageBox.Show("Unable to start web browser", "Launch Error", MessageBoxButtons.OK, diff --git a/Source/VBNetDemos/vCardBrowser/VCardPropertiesDlg.vb b/Source/VBNetDemos/vCardBrowser/VCardPropertiesDlg.vb index 16f60e8..1299754 100644 --- a/Source/VBNetDemos/vCardBrowser/VCardPropertiesDlg.vb +++ b/Source/VBNetDemos/vCardBrowser/VCardPropertiesDlg.vb @@ -114,7 +114,10 @@ Partial Public Class VCardPropertiesDlg MessageBox.Show("Enter a web page URL first", "No URL", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Else Try - System.Diagnostics.Process.Start(txtWebPage.Text) + Process.Start(New ProcessStartInfo With { + .FileName = txtWebPage.Text, + .UseShellExecute = True + }) Catch ex As Exception MessageBox.Show("Unable to start web browser for this URL", "URL Error", MessageBoxButtons.OK, diff --git a/Source/VBNetDemos/vCardBrowser/app.config b/Source/VBNetDemos/vCardBrowser/app.config index 9659fad..bf23e96 100644 --- a/Source/VBNetDemos/vCardBrowser/app.config +++ b/Source/VBNetDemos/vCardBrowser/app.config @@ -20,9 +20,6 @@ - - - diff --git a/Source/VBNetDemos/vCardBrowser/vCardBrowser.vbproj b/Source/VBNetDemos/vCardBrowser/vCardBrowser.vbproj index 8fbee95..b962505 100644 --- a/Source/VBNetDemos/vCardBrowser/vCardBrowser.vbproj +++ b/Source/VBNetDemos/vCardBrowser/vCardBrowser.vbproj @@ -1,7 +1,7 @@  WinExe - net6.0-windows;net40 + net8.0-windows;net40 true False False