Initial commit - Pingerino network monitoring application

هذا الالتزام موجود في:
Era
2025-08-19 07:34:27 +03:00
التزام 243f4787dd
41 ملفات معدلة مع 12352 إضافات و0 حذوفات

163
Utilities/UIHelper.cs Normal file
عرض الملف

@@ -0,0 +1,163 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Pingerino.Utilities
{
public static class UIHelper
{
// Windows API constants and imports for form dragging
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll")]
public static extern bool ReleaseCapture();
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
public static extern IntPtr CreateRoundRectRgn(
int nLeftRect, int nTopRect, int nRightRect, int nBottomRect,
int nWidthEllipse, int nHeightEllipse);
/// <summary>
/// Enables form dragging by mouse
/// </summary>
public static void EnableFormDragging(Form form, Control dragControl)
{
dragControl.MouseDown += (sender, e) =>
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(form.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
};
}
/// <summary>
/// Applies rounded corners to a form
/// </summary>
public static void ApplyRoundedCorners(Form form, int radius = 30)
{
form.Region = Region.FromHrgn(CreateRoundRectRgn(0, 0, form.Width, form.Height, radius, radius));
}
/// <summary>
/// Safely updates UI control from any thread
/// </summary>
public static void SafeInvoke(Control control, Action action)
{
if (control == null || control.IsDisposed)
return;
if (control.InvokeRequired)
{
try
{
control.Invoke(action);
}
catch (ObjectDisposedException)
{
// Control was disposed while trying to invoke
}
catch (InvalidOperationException)
{
// Control handle was not created or is being destroyed
}
}
else
{
action();
}
}
/// <summary>
/// Safely updates UI control from any thread with return value
/// </summary>
public static T SafeInvoke<T>(Control control, Func<T> func)
{
if (control == null || control.IsDisposed)
return default(T);
if (control.InvokeRequired)
{
try
{
return (T)control.Invoke(func);
}
catch (ObjectDisposedException)
{
return default(T);
}
catch (InvalidOperationException)
{
return default(T);
}
}
else
{
return func();
}
}
/// <summary>
/// Shows an error message with consistent styling
/// </summary>
public static void ShowError(string message, string title = "Error")
{
MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
/// <summary>
/// Shows an information message with consistent styling
/// </summary>
public static void ShowInformation(string message, string title = "Information")
{
MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
/// <summary>
/// Shows a confirmation dialog
/// </summary>
public static bool ShowConfirmation(string message, string title = "Confirm")
{
return MessageBox.Show(message, title, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes;
}
/// <summary>
/// Formats time span for display
/// </summary>
public static string FormatTimeSpan(TimeSpan timeSpan)
{
if (timeSpan.TotalDays >= 1)
return $"{timeSpan.Days}d {timeSpan.Hours}h {timeSpan.Minutes}m";
if (timeSpan.TotalHours >= 1)
return $"{timeSpan.Hours}h {timeSpan.Minutes}m {timeSpan.Seconds}s";
if (timeSpan.TotalMinutes >= 1)
return $"{timeSpan.Minutes}m {timeSpan.Seconds}s";
return $"{timeSpan.Seconds}.{timeSpan.Milliseconds:000}s";
}
/// <summary>
/// Formats bytes for display
/// </summary>
public static string FormatBytes(long bytes)
{
string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
int counter = 0;
decimal number = bytes;
while (Math.Round(number / 1024) >= 1)
{
number /= 1024;
counter++;
}
return $"{number:n1} {suffixes[counter]}";
}
}
}

عرض الملف

@@ -0,0 +1,90 @@
using System;
using System.Net;
using System.Text.RegularExpressions;
namespace Pingerino.Utilities
{
public static class ValidationHelper
{
private static readonly Regex IpAddressRegex = new Regex(
@"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",
RegexOptions.Compiled);
private static readonly Regex HostnameRegex = new Regex(
@"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$",
RegexOptions.Compiled);
public static bool IsValidIpAddress(string ipAddress)
{
if (string.IsNullOrWhiteSpace(ipAddress))
return false;
return IPAddress.TryParse(ipAddress, out _) || IpAddressRegex.IsMatch(ipAddress);
}
public static bool IsValidHostname(string hostname)
{
if (string.IsNullOrWhiteSpace(hostname))
return false;
if (hostname.Length > 253)
return false;
return HostnameRegex.IsMatch(hostname);
}
public static bool IsValidIpAddressOrHostname(string address)
{
return IsValidIpAddress(address) || IsValidHostname(address);
}
public static bool IsValidPingInterval(string intervalText, out int interval)
{
interval = 0;
if (string.IsNullOrWhiteSpace(intervalText))
return false;
if (!int.TryParse(intervalText, out interval))
return false;
return interval >= 100 && interval <= 60000; // 100ms to 60 seconds
}
public static bool IsValidPingInterval(int interval)
{
return interval >= 100 && interval <= 60000;
}
public static string SanitizeInput(string input)
{
if (string.IsNullOrEmpty(input))
return string.Empty;
return input.Trim();
}
public static string GetValidationErrorMessage(string fieldName, string value)
{
if (string.IsNullOrWhiteSpace(value))
return $"{fieldName} cannot be empty.";
switch (fieldName.ToLower())
{
case "ip address":
case "ipaddress":
if (!IsValidIpAddressOrHostname(value))
return "Please enter a valid IP address or hostname.";
break;
case "interval":
case "ping interval":
if (!IsValidPingInterval(value, out _))
return "Ping interval must be between 100 and 60000 milliseconds.";
break;
}
return null;
}
}
}