Initial Fill

This commit is contained in:
Black_Betty committed 2026-09-29 19:19:16 +02:00
commit 976b651e4b
15 files changed
+1128

No files matched your search

+76
View File
@@ -0,0 +1,76 @@
# .gitignore for Visual Studio / .NET projects
# Generated minimal .gitignore
## Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
.vs/
*.user
*.suo
*.userosscache
*.sln.docstates
# Build results
[Bb]in/
[Oo]bj/
project.lock.json
project.fragment.lock.json
artifacts/
# NuGet
*.nupkg
packages/
# Visual Studio code coverage
*.coverage
*.coveragexml
# MSTest test results
TestResults/
# Rider
.idea/
# Resharper
_ReSharper*/
*.[Rr]e[Ss]harper
# DotCover
*.dotCover
# Others
*.log
*.tmp
*.temp
*.cache
*.bak
*.swp
.DS_Store
# Windows image file caches
Thumbs.db
# User-specific files
*.aps
*.ncb
*.opendb
*.opensdf
# IIS Express
/.vs/**/applicationhost.config
# Node
node_modules/
# git LFS
*.psd
# Ignore NuGet packages folder
**/packages/*
# Ignore published output
publish/
# Ignore JetBrains Rider settings
.idea/
# Keep the file simple; add more entries as needed
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
</configuration>
+9
View File
@@ -0,0 +1,9 @@
<Application x:Class="TapeCatalog.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TapeCatalog"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
+17
View File
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace TapeCatalog
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
+62
View File
@@ -0,0 +1,62 @@
<Window x:Class="TapeCatalog.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TapeCatalog"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TabControl>
<TabItem Header="SRC-ARC">
<Grid Background="#FFE5E5E5">
<TextBox x:Name="SourceTextBox" HorizontalAlignment="Left" Margin="0,19,0,0" TextWrapping="Wrap" Text="Source Directory" VerticalAlignment="Top" Width="507" Height="20"/>
<TextBox x:Name="ArchiveTextBox" HorizontalAlignment="Left" Height="20" Margin="0,56,0,0" TextWrapping="Wrap" Text="Archive Directory" VerticalAlignment="Top" Width="507"/>
<Button x:Name="SourceSelect" Content="Select Directory" HorizontalAlignment="Left" Margin="512,19,0,0" VerticalAlignment="Top" Height="20" Click="SET_RES_DIR"/>
<Button x:Name="ArchiveSelect" Content="Select Directory" HorizontalAlignment="Left" Margin="512,56,0,0" VerticalAlignment="Top" Height="20" Click="SET_ARC_DIR"/>
<Button Content="Scan Source" HorizontalAlignment="Left" Height="22" Margin="700,146,0,0" VerticalAlignment="Top" Width="76" Click="SCAN_RES_DIR" RenderTransformOrigin="2.316,5.185" Grid.Column="1"/>
<Button Content="Scan Archive" HorizontalAlignment="Left" Height="22" Margin="700,168,0,0" VerticalAlignment="Top" Width="76" Click="SCAN_ARC_DIR" Grid.Column="1"/>
<Button Content="Clear List" HorizontalAlignment="Left" Height="22" Margin="700,190,0,0" VerticalAlignment="Top" Width="76" Click="CLEAR_FILES" Grid.Column="1"/>
<Button Content="Verify Sizes" HorizontalAlignment="Left" Height="22" Margin="700,212,0,0" VerticalAlignment="Top" Width="76" Click="VERIFY_SIZES" Grid.Column="1"/>
<Button Content="Export XML" HorizontalAlignment="Left" Height="22" Margin="700,234,0,0" VerticalAlignment="Top" Width="76" Click="EXPORT_LIST" Grid.Column="1"/>
<Button Content="Import XML" HorizontalAlignment="Left" Height="22" Margin="700,256,0,0" VerticalAlignment="Top" Width="76" Click="IMPORT_LIST" Grid.Column="1"/>
<Button Content="-> TapeCat" HorizontalAlignment="Left" Height="22" Margin="700,278,0,0" VerticalAlignment="Top" Width="76" Click="COPY_TO_TAPECATALOG" Grid.Column="1"/>
<ListView x:Name="FilesListView" Margin="10,146,101,10" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn Header="Filename" DisplayMemberBinding="{Binding Filename}" Width="300"/>
<GridViewColumn Header="File Dir" DisplayMemberBinding="{Binding FileDir}" Width="300"/>
<GridViewColumn Header="Size SRC (MB)" DisplayMemberBinding="{Binding SizeSrc}" Width="100"/>
<GridViewColumn Header="Size ARC (MB)" DisplayMemberBinding="{Binding SizeArc}" Width="100"/>
<GridViewColumn Header="Status" DisplayMemberBinding="{Binding Status}" Width="60"/>
<GridViewColumn Header="Archive Drive" DisplayMemberBinding="{Binding ArcDrive}" Width="140"/>
<GridViewColumn Header="Mod SRC" DisplayMemberBinding="{Binding ModSrc}" Width="140"/>
<GridViewColumn Header="Mod ARC" DisplayMemberBinding="{Binding ModArc}" Width="140"/>
</GridView>
</ListView.View>
</ListView>
<TextBlock TextWrapping="Wrap" Text="Source Directory:" Margin="0,0,697,387"/>
<TextBlock TextWrapping="Wrap" Text="Archive Directory:" Margin="0,37,697,350"/>
</Grid>
</TabItem>
<TabItem Header="Tapecatalog">
<Grid Background="#FFE5E5E5">
<ComboBox x:Name="MediumComboBox" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="200" Grid.ColumnSpan="2"/>
<Button Content="Refresh Mediums" HorizontalAlignment="Left" Height="22" Margin="218,10,0,0" VerticalAlignment="Top" Width="120" Click="REFRESH_MEDIUMS"/>
<Button Content="Copy from SRC-ARC" HorizontalAlignment="Left" Height="22" Margin="343,10,0,0" VerticalAlignment="Top" Width="120" Click="COPY_FROM_SRCARC"/>
<ListView x:Name="TapeCatalogListView" Margin="10,44,10,40" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn Header="Medium" DisplayMemberBinding="{Binding Medium}" Width="150"/>
<GridViewColumn Header="Dateiname" DisplayMemberBinding="{Binding Filename}" Width="400"/>
<GridViewColumn Header="Änderungsdatum" DisplayMemberBinding="{Binding Modified}" Width="200"/>
</GridView>
</ListView.View>
</ListView>
<Button Content="Export Medium" HorizontalAlignment="Left" Height="22" Margin="468,0,0,374" VerticalAlignment="Bottom" Width="120" Click="EXPORT_MEDIUM"/>
</Grid>
</TabItem>
</TabControl>
</Grid>
</Window>
+364
View File
@@ -0,0 +1,364 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.IO;
using XML;
namespace TapeCatalog
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly ObservableCollection<FileEntry> _files = new ObservableCollection<FileEntry>();
private static string FormatBytesToMb(long bytes)
{
// convert to MB with two decimal places
double mb = bytes / 1024.0 / 1024.0;
return mb.ToString("F2");
}
public MainWindow()
{
InitializeComponent();
FilesListView.ItemsSource = _files;
}
#region (export Medium)
private void EXPORT_MEDIUM(object sender, RoutedEventArgs e)
{
var selected = MediumComboBox.SelectedItem as string;
if (string.IsNullOrWhiteSpace(selected))
{
MessageBox.Show(this, "Bitte ein Medium im Dropdown auswählen.", "Keine Auswahl", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// collect matching entries from TapeCatalogListView
var matches = new List<XML.Methods.TapeEntry>();
foreach (var item in TapeCatalogListView.Items)
{
var te = item as dynamic;
if (te == null) continue;
string m = te.Medium as string;
if (string.Equals(m, selected, StringComparison.OrdinalIgnoreCase))
{
matches.Add(new XML.Methods.TapeEntry { Medium = te.Medium, Filename = te.Filename, Modified = te.Modified });
}
}
if (matches.Count == 0)
{
MessageBox.Show(this, "Keine Einträge für das gewählte Medium gefunden.", "Keine Einträge", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// delegate export to XML helper
XML.Methods.ExportTapeEntries(this, selected, matches);
}
#endregion
#region (Import List)
private void IMPORT_LIST(object sender, RoutedEventArgs e)
{
// delegate to XML import helper
XML.Methods.ImportList(this, _files, SourceTextBox, ArchiveTextBox);
}
#endregion (Import List)
#region (COPY_TO_TAPECATALOG)
private void COPY_TO_TAPECATALOG(object sender, RoutedEventArgs e)
{
// delegate to XML helper to copy entries to TapeCatalog list view
XML.Methods.CopyToTapeCatalog(this, _files, TapeCatalogListView);
}
#endregion (COPY_TO_TAPECATALOG)
#region (COPY_FROM_SRCARC)
private void COPY_FROM_SRCARC(object sender, RoutedEventArgs e)
{
XML.Methods.CopyToTapeCatalog(this, _files, TapeCatalogListView);
}
#endregion (COPY_FROM_SRCARC)
#region (REFRESH_MEDIUMS)
private void REFRESH_MEDIUMS(object sender, RoutedEventArgs e)
{
// collect distinct mediums from TapeCatalogListView items
try
{
var mediums = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var item in TapeCatalogListView.Items)
{
var te = item as dynamic;
if (te == null) continue;
string m = te.Medium as string;
if (!string.IsNullOrWhiteSpace(m)) mediums.Add(m);
}
MediumComboBox.ItemsSource = mediums.OrderBy(s => s).ToList();
}
catch (Exception ex)
{
MessageBox.Show(this, $"Fehler beim Aktualisieren der Medium-Liste: {ex.Message}", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
#endregion (REFRESH_MEDIUMS)
#region (EXPORT_LIST)
private void EXPORT_LIST(object sender, RoutedEventArgs e)
{
// Delegate export to XML helper
XML.Methods.ExportList(this, SourceTextBox.Text, ArchiveTextBox.Text, _files);
}
private void SET_RES_DIR(object sender, RoutedEventArgs e)
{
// Use the WinForms FolderBrowserDialog to select a folder
using (var dlg = new System.Windows.Forms.FolderBrowserDialog())
{
dlg.Description = "Select a folder";
dlg.ShowNewFolderButton = true;
var result = dlg.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK && !string.IsNullOrWhiteSpace(dlg.SelectedPath))
{
SourceTextBox.Text = dlg.SelectedPath;
}
}
}
#endregion (EXPORT_LIST)
#region (SET_ARC_DIR)
private void SET_ARC_DIR(object sender, RoutedEventArgs e)
{
// Use the WinForms FolderBrowserDialog to select a folder
using (var dlg = new System.Windows.Forms.FolderBrowserDialog())
{
dlg.Description = "Select a folder";
dlg.ShowNewFolderButton = true;
var result = dlg.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK && !string.IsNullOrWhiteSpace(dlg.SelectedPath))
{
ArchiveTextBox.Text = dlg.SelectedPath;
}
}
}
#endregion (SET_ARC_DIR)
#region (SCAN_RES_DIR)
private void SCAN_RES_DIR(object sender, RoutedEventArgs e)
{
var path = SourceTextBox.Text?.Trim();
if (string.IsNullOrWhiteSpace(path))
{
MessageBox.Show("Please select a directory first.", "No directory", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
if (!Directory.Exists(path))
{
MessageBox.Show("The specified directory does not exist.", "Directory not found", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
try
{
foreach (var file in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories))
{
try
{
var fi = new FileInfo(file);
// check if an entry with same filename and same source directory already exists
var existing = _files.FirstOrDefault(f => string.Equals(f.Filename, fi.Name, StringComparison.OrdinalIgnoreCase)
&& string.Equals(f.FileDir, fi.DirectoryName, StringComparison.OrdinalIgnoreCase));
if (existing != null)
{
var newSizeMb = FormatBytesToMb(fi.Length);
if (existing.SizeSrc != newSizeMb)
{
// update size and modification date, do not add a new entry
existing.SizeSrc = newSizeMb;
existing.ModSrc = fi.LastWriteTime.ToString();
// reset verification status and archive drive info
existing.Status = string.Empty;
existing.ArcDrive = string.Empty;
}
}
else
{
_files.Add(new FileEntry
{
Filename = fi.Name,
FileDir = fi.DirectoryName,
SizeSrc = FormatBytesToMb(fi.Length),
//SizeArc = string.Empty,
ModSrc = fi.LastWriteTime.ToString(),
//ModArc = string.Empty
});
}
}
catch
{
// ignore files we can't access
}
}
}
catch (Exception ex)
{
MessageBox.Show($"Error scanning directory: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
// inform user that scan finished
MessageBox.Show($"Scan abgeschlossen. Einträge: {_files.Count}", "Scan beendet", MessageBoxButton.OK, MessageBoxImage.Information);
}
#endregion (SCAN_RES_DIR)
#region(SCAN_ARC_DIR)
private void SCAN_ARC_DIR(object sender, RoutedEventArgs e)
{
var path = ArchiveTextBox.Text?.Trim();
if (string.IsNullOrWhiteSpace(path))
{
MessageBox.Show("Please select an archive directory first.", "No directory", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
if (!Directory.Exists(path))
{
MessageBox.Show("The specified archive directory does not exist.", "Directory not found", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
try
{
foreach (var file in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories))
{
try
{
var fi = new FileInfo(file);
// look for existing entry by filename (case-insensitive)
var existing = _files.FirstOrDefault(f => string.Equals(f.Filename, fi.Name, StringComparison.Ordinal));
if (existing != null)
{
// update SizeArc
existing.SizeArc = FormatBytesToMb(fi.Length);
// update ModArc to the most recent modified date
DateTime prevMod;
if (!DateTime.TryParse(existing.ModArc, out prevMod))
prevMod = DateTime.MinValue;
var mod = fi.LastWriteTime > prevMod ? fi.LastWriteTime : prevMod;
existing.ModArc = mod.ToString();
}
else
{
_files.Add(new FileEntry
{
Filename = fi.Name,
FileDir = fi.DirectoryName,
//SizeSrc = string.Empty,
SizeArc = FormatBytesToMb(fi.Length),
//ModSrc = string.Empty,
ModArc = fi.LastWriteTime.ToString()
});
}
}
catch
{
// ignore inaccessible files
}
}
}
catch (Exception ex)
{
MessageBox.Show($"Error scanning archive directory: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
// inform user that archive scan finished
MessageBox.Show($"Scan abgeschlossen. Einträge: {_files.Count}", "Scan beendet", MessageBoxButton.OK, MessageBoxImage.Information);
}
#endregion(SCAN_ARC_DIR)
#region (CLEAR_FILES)
private void CLEAR_FILES(object sender, RoutedEventArgs e)
{
_files.Clear();
}
#endregion (CLEAR_FILES)
#region (VERIFY_SIZES)
private void VERIFY_SIZES(object sender, RoutedEventArgs e)
{
// determine archive drive name (volume label or drive root)
string archivePath = ArchiveTextBox.Text?.Trim();
string archiveDriveName = string.Empty;
if (!string.IsNullOrWhiteSpace(archivePath))
{
try
{
var root = System.IO.Path.GetPathRoot(archivePath);
if (!string.IsNullOrWhiteSpace(root))
{
try
{
var di = new DriveInfo(root);
archiveDriveName = string.IsNullOrWhiteSpace(di.VolumeLabel) ? root.TrimEnd('\\') : di.VolumeLabel;
}
catch
{
archiveDriveName = root.TrimEnd('\\');
}
}
}
catch
{
archiveDriveName = string.Empty;
}
}
foreach (var entry in _files)
{
// Sizes are stored in MB with two decimals; compare as doubles
double src = 0;
double arc = 0;
double.TryParse(entry.SizeSrc, out src);
double.TryParse(entry.SizeArc, out arc);
if (src > 0 && arc > 0 && Math.Abs(src - arc) < 0.01)
{
entry.Status = "✔";
entry.ArcDrive = archiveDriveName;
}
else
{
entry.Status = "✖";
entry.ArcDrive = string.Empty;
}
}
}
}
#endregion (VERIFY_SIZES)
public class FileEntry : System.ComponentModel.INotifyPropertyChanged
{
public string Filename { get; set; }
public string FileDir { get; set; }
private string _sizeSrc;
public string SizeSrc { get => _sizeSrc; set { _sizeSrc = value; OnPropertyChanged(nameof(SizeSrc)); } }
private string _sizeArc;
public string SizeArc { get => _sizeArc; set { _sizeArc = value; OnPropertyChanged(nameof(SizeArc)); } }
public string ModSrc { get; set; }
public string ModArc { get; set; }
private string _status;
public string Status { get => _status; set { _status = value; OnPropertyChanged(nameof(Status)); } }
private string _arcDrive;
public string ArcDrive { get => _arcDrive; set { _arcDrive = value; OnPropertyChanged(nameof(ArcDrive)); } }
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName) => PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propName));
}
}
+52
View File
@@ -0,0 +1,52 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TapeCatalog")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TapeCatalog")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+71
View File
@@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TapeCatalog.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// 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", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TapeCatalog.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}
+117
View File
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+30
View File
@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TapeCatalog.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}
+7
View File
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
+8
View File
@@ -0,0 +1,8 @@
using System;
public class Class1
{
public Class1()
{
}
}
+103
View File
@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2ED075BB-CE1E-4B8C-B81C-E0BEA77D1685}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>TapeCatalog</RootNamespace>
<AssemblyName>TapeCatalog</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="XML_Methods.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include=".gitignore" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+3
View File
@@ -0,0 +1,3 @@
<Solution>
<Project Path="TapeCatalog.csproj" Id="2ed075bb-ce1e-4b8c-b81c-e0bea77d1685" />
</Solution>
+203
View File
@@ -0,0 +1,203 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Windows.Controls;
using System.Windows;
using Microsoft.Win32;
using System.Collections.ObjectModel;
using TapeCatalog;
namespace XML
{
public static class Methods
{
public class TapeEntry
{
public string Medium { get; set; }
public string Filename { get; set; }
public string Modified { get; set; }
}
public static void ExportTapeEntries(Window owner, string medium, IEnumerable<TapeEntry> entries)
{
if (entries == null) return;
var dlg = new Microsoft.Win32.SaveFileDialog()
{
Filter = "XML Files (*.xml)|*.xml|All Files (*.*)|*.*",
DefaultExt = "xml",
AddExtension = true,
FileName = $"tape_{medium}.xml"
};
var res = dlg.ShowDialog(owner);
if (res != true) return;
try
{
var doc = new XDocument(
new XElement("TapeEntries",
new XElement("Medium", medium ?? string.Empty),
entries.Select(e => new XElement("Entry",
new XElement("Medium", e.Medium ?? string.Empty),
new XElement("Filename", e.Filename ?? string.Empty),
new XElement("Modified", e.Modified ?? string.Empty)
))
)
);
doc.Save(dlg.FileName);
MessageBox.Show(owner, $"Export erfolgreich nach {dlg.FileName}", "Export", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
MessageBox.Show(owner, $"Fehler beim Export: {ex.Message}", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public static void CopyToTapeCatalog(Window owner, IEnumerable<FileEntry> sourceFiles, ListView targetListView)
{
if (sourceFiles == null || targetListView == null) return;
// add entries: Medium = ArcDrive, Dateiname = Filename, Änderungsdatum = SizeArc (archive size)
foreach (var f in sourceFiles)
{
try
{
var te = new TapeEntry
{
Medium = f.ArcDrive ?? string.Empty,
Filename = f.Filename ?? string.Empty,
Modified = f.SizeArc ?? string.Empty
};
// add to ListView on UI thread
if (!targetListView.Dispatcher.CheckAccess())
{
targetListView.Dispatcher.Invoke(() => targetListView.Items.Add(te));
}
else
{
targetListView.Items.Add(te);
}
}
catch
{
// ignore malformed entries
}
}
}
public static void ImportList(Window owner, ObservableCollection<FileEntry> files, TextBox sourceTextBox, TextBox archiveTextBox)
{
if (files == null) return;
if (files.Count > 0)
{
var ask = MessageBox.Show(owner, "Aktuelle Liste speichern?\nJa = speichern, Nein = löschen, Abbrechen = abbrechen.", "Liste vorhanden", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
if (ask == MessageBoxResult.Cancel) return;
if (ask == MessageBoxResult.Yes)
{
// save current list
ExportList(owner, sourceTextBox?.Text ?? string.Empty, archiveTextBox?.Text ?? string.Empty, files);
files.Clear();
}
else if (ask == MessageBoxResult.No)
{
files.Clear();
}
}
var dlg = new Microsoft.Win32.OpenFileDialog()
{
Filter = "XML Files (*.xml)|*.xml|All Files (*.*)|*.*",
DefaultExt = "xml",
Multiselect = false
};
var res = dlg.ShowDialog(owner);
if (res != true) return;
try
{
var doc = XDocument.Load(dlg.FileName);
var root = doc.Element("Files");
if (root == null) return;
var src = root.Element("SourceDir")?.Value ?? string.Empty;
var arc = root.Element("ArchiveDir")?.Value ?? string.Empty;
if (sourceTextBox != null) sourceTextBox.Text = src;
if (archiveTextBox != null) archiveTextBox.Text = arc;
foreach (var fe in root.Elements("File"))
{
try
{
var entry = new FileEntry
{
Filename = fe.Element("Filename")?.Value ?? string.Empty,
FileDir = fe.Element("FileDir")?.Value ?? string.Empty,
SizeSrc = fe.Element("SizeSrc")?.Value ?? string.Empty,
SizeArc = fe.Element("SizeArc")?.Value ?? string.Empty,
Status = fe.Element("Status")?.Value ?? string.Empty,
ArcDrive = fe.Element("ArcDrive")?.Value ?? string.Empty,
ModSrc = fe.Element("ModSrc")?.Value ?? string.Empty,
ModArc = fe.Element("ModArc")?.Value ?? string.Empty
};
files.Add(entry);
}
catch
{
// ignore malformed entries
}
}
MessageBox.Show(owner, $"Import erfolgreich von {dlg.FileName}", "Import", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
MessageBox.Show(owner, $"Fehler beim Import: {ex.Message}", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public static void ExportList(Window owner, string sourceDir, string archiveDir, IEnumerable<FileEntry> files)
{
var dlg = new SaveFileDialog()
{
Filter = "XML Files (*.xml)|*.xml|All Files (*.*)|*.*",
DefaultExt = "xml",
AddExtension = true,
FileName = "filelist.xml"
};
var res = dlg.ShowDialog(owner);
if (res != true)
return;
try
{
var doc = new XDocument(
new XElement("Files",
new XElement("SourceDir", sourceDir ?? string.Empty),
new XElement("ArchiveDir", archiveDir ?? string.Empty),
files.Select(f => new XElement("File",
new XElement("Filename", f.Filename ?? string.Empty),
new XElement("FileDir", f.FileDir ?? string.Empty),
new XElement("SizeSrc", f.SizeSrc ?? string.Empty),
new XElement("SizeArc", f.SizeArc ?? string.Empty),
new XElement("Status", f.Status ?? string.Empty),
new XElement("ArcDrive", f.ArcDrive ?? string.Empty),
new XElement("ModSrc", f.ModSrc ?? string.Empty),
new XElement("ModArc", f.ModArc ?? string.Empty)
))
)
);
doc.Save(dlg.FileName);
MessageBox.Show(owner, $"Export erfolgreich nach {dlg.FileName}", "Export", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
MessageBox.Show(owner, $"Fehler beim Export: {ex.Message}", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}