diff --git a/Navferty.Common/Controls/CheckedListBoxEx.cs b/Navferty.Common/Controls/CheckedListBoxEx.cs
index b6d3ef9..0107c98 100644
--- a/Navferty.Common/Controls/CheckedListBoxEx.cs
+++ b/Navferty.Common/Controls/CheckedListBoxEx.cs
@@ -2,6 +2,9 @@
using System.Drawing;
using System.Windows.Forms;
+using Navferty.Common.WinAPI;
+using Navferty.Common.WinAPI.GDI;
+
#nullable enable
namespace Navferty.Common.Controls
@@ -47,19 +50,18 @@ protected override void WndProc(ref Message m)
base.WndProc(ref m);
//Now do our job.
- switch ((WinAPI.WindowMessages)m.Msg)
+ switch ((Windows.WindowMessages)m.Msg)
{
- case WinAPI.WindowMessages.WM_PAINT: RePaint(); break;
+ case Windows.WindowMessages.WM_PAINT: RePaint(); break;
}
}
private void RePaint()
{
if (Items.Count > 0 || string.IsNullOrWhiteSpace(emptyText))
- return;//We paint over only if ListBox noes not have any items and and EmptyText
+ return; //We paint over only if ListBox noes not have any items and and EmptyText
- //var rcClient = WinAPI.GetClientRect(this);
- using (var dc = new WinAPI.DC(this))
+ using (var dc = this.GetDC())
using (var g = dc.CreateGraphics())
{
g.PageUnit = GraphicsUnit.Pixel;
diff --git a/Navferty.Common/Controls/ErrorDialog.cs b/Navferty.Common/Controls/ErrorDialog.cs
new file mode 100644
index 0000000..9169c14
--- /dev/null
+++ b/Navferty.Common/Controls/ErrorDialog.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Drawing;
+
+using Navferty.Common.Feedback;
+
+#nullable enable
+
+namespace Navferty.Common.Controls
+{
+ internal class ErrorDialog : FormEx
+ {
+ private System.Windows.Forms.Button btnOk;
+ private System.Windows.Forms.Label lblMessage;
+ private System.Windows.Forms.PictureBox picIcon;
+ private System.Windows.Forms.TableLayoutPanel tlpMessage;
+ private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
+ private System.Windows.Forms.LinkLabel llSendErrorReport;
+ private System.Windows.Forms.Label lblHeader;
+ private System.Windows.Forms.TableLayoutPanel tlpMain;
+
+ internal ErrorDialog() : base()
+ {
+ InitializeComponent();
+
+ picIcon!.Image = SystemIcons.Exclamation.ToBitmap();
+ lblMessage!.Text = string.Empty;
+ lblMessage!.BackColor = SystemColors.Window;
+ llSendErrorReport!.Text = Localization.UIStrings.Feedback_SendFeedback;
+ btnOk!.Text = Localization.UIStrings.ErrorWindow_OkButton;
+ }
+
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ErrorDialog));
+ this.tlpMain = new System.Windows.Forms.TableLayoutPanel();
+ this.lblHeader = new System.Windows.Forms.Label();
+ this.tlpMessage = new System.Windows.Forms.TableLayoutPanel();
+ this.lblMessage = new System.Windows.Forms.Label();
+ this.picIcon = new System.Windows.Forms.PictureBox();
+ this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
+ this.btnOk = new System.Windows.Forms.Button();
+ this.llSendErrorReport = new System.Windows.Forms.LinkLabel();
+ this.tlpMain.SuspendLayout();
+ this.tlpMessage.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.picIcon)).BeginInit();
+ this.tableLayoutPanel1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // tlpMain
+ //
+ this.tlpMain.AutoSize = true;
+ this.tlpMain.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.tlpMain.ColumnCount = 1;
+ this.tlpMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tlpMain.Controls.Add(this.lblHeader, 0, 0);
+ this.tlpMain.Controls.Add(this.tlpMessage, 0, 1);
+ this.tlpMain.Controls.Add(this.tableLayoutPanel1, 0, 2);
+ this.tlpMain.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.tlpMain.Location = new System.Drawing.Point(0, 0);
+ this.tlpMain.Name = "tlpMain";
+ this.tlpMain.RowCount = 3;
+ this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
+ this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
+ this.tlpMain.Size = new System.Drawing.Size(384, 161);
+ this.tlpMain.TabIndex = 0;
+ //
+ // lblHeader
+ //
+ this.lblHeader.AutoSize = true;
+ this.lblHeader.Dock = System.Windows.Forms.DockStyle.Top;
+ this.lblHeader.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.lblHeader.ForeColor = System.Drawing.SystemColors.HotTrack;
+ this.lblHeader.Location = new System.Drawing.Point(3, 0);
+ this.lblHeader.Name = "lblHeader";
+ this.lblHeader.Padding = new System.Windows.Forms.Padding(8);
+ this.lblHeader.Size = new System.Drawing.Size(378, 35);
+ this.lblHeader.TabIndex = 5;
+ this.lblHeader.Text = "label1";
+ this.lblHeader.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // tlpMessage
+ //
+ this.tlpMessage.AutoSize = true;
+ this.tlpMessage.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.tlpMessage.BackColor = System.Drawing.SystemColors.Window;
+ this.tlpMessage.ColumnCount = 3;
+ this.tlpMessage.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 8F));
+ this.tlpMessage.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
+ this.tlpMessage.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tlpMessage.Controls.Add(this.lblMessage, 2, 0);
+ this.tlpMessage.Controls.Add(this.picIcon, 1, 0);
+ this.tlpMessage.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.tlpMessage.Location = new System.Drawing.Point(3, 38);
+ this.tlpMessage.Name = "tlpMessage";
+ this.tlpMessage.RowCount = 1;
+ this.tlpMessage.RowStyles.Add(new System.Windows.Forms.RowStyle());
+ this.tlpMessage.Size = new System.Drawing.Size(378, 66);
+ this.tlpMessage.TabIndex = 3;
+ //
+ // lblMessage
+ //
+ this.lblMessage.AutoSize = true;
+ this.lblMessage.BackColor = System.Drawing.SystemColors.Info;
+ this.lblMessage.Dock = System.Windows.Forms.DockStyle.Left;
+ this.lblMessage.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.lblMessage.Location = new System.Drawing.Point(47, 0);
+ this.lblMessage.Name = "lblMessage";
+ this.lblMessage.Padding = new System.Windows.Forms.Padding(8);
+ this.lblMessage.Size = new System.Drawing.Size(68, 66);
+ this.lblMessage.TabIndex = 1;
+ this.lblMessage.Text = "label1";
+ this.lblMessage.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // picIcon
+ //
+ this.picIcon.Dock = System.Windows.Forms.DockStyle.Left;
+ this.picIcon.Image = ((System.Drawing.Image)(resources.GetObject("picIcon.Image")));
+ this.picIcon.Location = new System.Drawing.Point(11, 3);
+ this.picIcon.Name = "picIcon";
+ this.picIcon.Size = new System.Drawing.Size(30, 60);
+ this.picIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
+ this.picIcon.TabIndex = 2;
+ this.picIcon.TabStop = false;
+ //
+ // tableLayoutPanel1
+ //
+ this.tableLayoutPanel1.ColumnCount = 2;
+ this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
+ this.tableLayoutPanel1.Controls.Add(this.btnOk, 1, 0);
+ this.tableLayoutPanel1.Controls.Add(this.llSendErrorReport, 0, 0);
+ this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 110);
+ this.tableLayoutPanel1.Name = "tableLayoutPanel1";
+ this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(8);
+ this.tableLayoutPanel1.RowCount = 1;
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tableLayoutPanel1.Size = new System.Drawing.Size(378, 48);
+ this.tableLayoutPanel1.TabIndex = 4;
+ //
+ // btnOk
+ //
+ this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
+ this.btnOk.Dock = System.Windows.Forms.DockStyle.Right;
+ this.btnOk.Location = new System.Drawing.Point(285, 11);
+ this.btnOk.Name = "btnOk";
+ this.btnOk.Size = new System.Drawing.Size(82, 26);
+ this.btnOk.TabIndex = 0;
+ this.btnOk.Text = "Close";
+ this.btnOk.UseVisualStyleBackColor = true;
+ //
+ // llSendErrorReport
+ //
+ this.llSendErrorReport.AutoSize = true;
+ this.llSendErrorReport.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.llSendErrorReport.Location = new System.Drawing.Point(11, 27);
+ this.llSendErrorReport.Name = "llSendErrorReport";
+ this.llSendErrorReport.Size = new System.Drawing.Size(268, 13);
+ this.llSendErrorReport.TabIndex = 1;
+ this.llSendErrorReport.TabStop = true;
+ this.llSendErrorReport.Text = "Send error report";
+ this.llSendErrorReport.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.llSendErrorReport_LinkClicked);
+ //
+ // ErrorForm
+ //
+ this.AcceptButton = this.btnOk;
+ this.AutoSize = true;
+ this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.ClientSize = new System.Drawing.Size(384, 161);
+ this.Controls.Add(this.tlpMain);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.MinimumSize = new System.Drawing.Size(400, 200);
+ this.Name = "ErrorForm";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.tlpMain.ResumeLayout(false);
+ this.tlpMain.PerformLayout();
+ this.tlpMessage.ResumeLayout(false);
+ this.tlpMessage.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.picIcon)).EndInit();
+ this.tableLayoutPanel1.ResumeLayout(false);
+ this.tableLayoutPanel1.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ private readonly Exception? Err = null;
+ private readonly bool AllowErrorReporting = false;
+
+ internal ErrorDialog(Exception ex, string? title, bool allowErrorReporting = true) : this()
+ {
+ Err = ex;
+ AllowErrorReporting = allowErrorReporting && (null != Err);
+ Text = Localization.UIStrings.ErrorWindow_Title;
+ bool HasTitle = !string.IsNullOrWhiteSpace(title);
+ {
+ lblHeader.Visible = HasTitle;
+ if (HasTitle) lblHeader.Text = title;
+ }
+ lblMessage.Text = (null == Err) ? "Unknown Error!" : ex.Message;
+ llSendErrorReport.Visible = allowErrorReporting;
+ }
+
+ private void llSendErrorReport_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
+ {
+ if (AllowErrorReporting) FeedbackManager.ShowFeedbackUI(Err?.Message);
+ }
+ }
+}
diff --git a/Navferty.Common/Controls/ErrorDialog.resx b/Navferty.Common/Controls/ErrorDialog.resx
new file mode 100644
index 0000000..89b4a3c
--- /dev/null
+++ b/Navferty.Common/Controls/ErrorDialog.resx
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
+ vAAADrwBlbxySQAACNxJREFUWEfFV2lsVNcV5l8gJJAEkkgRQmxOAjisYTGLMWFx2KFlKYsS/0hoFKRE
+ +ZEGEqJUQipUVIkaERpq4w3HC96wwfUA9ixexzNjj+0Zz3jswZ4ZL9gem63UBWPe1+88v3EtQltQVfVI
+ R8+ed+/5vrPe+0Y9qRz6+OMwagz1FNVI9VPvaSp/y2/yTtaEadv+e6GxqN98/nn8kcOHbyckJPQbjcaH
+ TU1NuNHXhwcPHqgqf8tv8k7WyFrZI3s1M08v3Dzt6NGjP/7+xIlbBoPhYW8wqAQ9jUp7cbHiTUuH+4fT
+ cP7uBGq+/gb1J/8AT3IS/Hqj0uPxKL09PYrskb1iQ2xpZp9MuGHNsWPHGnWFhQM3e3uVjpJS+HOy0XU2
+ Hr5PP4X/wAEEfrET/h3b0bptG5qpru07YN+xA+b334cjKUnxmSuV6+3titgQW2JTM//vhQu3njh+vMfh
+ cCi9tbVozTiP3uRktH34IToJ0E6w9i3b4NuyBa1UL7V5w2Y0btwI14ZoOKOjYd2wAaWbNqH222/RZauG
+ 2BKbYluDebwIS1no9/sRKChAe2oaOr44jA4NOLB1qwrcsnkzvARoJpD73XfRQFDHunWoo9rXrIHtnXdg
+ XbUKJfz7L+vWw5udDbGpkXh8JPhimoRK2Krg8fEIHPw1OrcTdP16NK1cCe/atUPABPVEE5i/O9asRR2B
+ 7AStXrMa5mXLUD53PkoXLULpihXQc1/Bqih4s7LUSGjp+HlNSLFIviTszd99h7aPPlI9bo6KRDfD//f8
+ fLTzWb88Am4COwkaArZGRcFCj8sWLoSVewIkb99/AFdmzUTR4sXQLY1AXuQqdFutEAzB0mCHhIyipGKl
+ 4FynT6Ptq6/g28Tcrl6NThYVrl+HKt3d8O7bBwuBQsBV9NAcuRIl8+ahipG5ZjSi5UYvfHSkcucuXHzz
+ TVxasAB5b7+Nwl/uhGAIlmBq8KNGSc/q9fqHnZYqNB/5Eq3MsYD79uwBenqGwENyvQvu/ftRMWcOqiIj
+ Uc6Qm+aEw7xhI66VlKCprQ3OhgY4OBc8Vguusj6yw8KQNTscOQsWojHlJ0iLCqYKTiZhMjiC3d1KU1oa
+ mmNi0By9Di7mr2XPr4A7dzTkf8q9ri44SaKY3hXPnoVyFmNzaSma2tvRQPDamhp0cM3du3eRy3epU6ci
+ ddYsZJCEbs8uyJwQTMEWAjEyvXo8TbAfOgQ3C83FYnJIUTFszR98ANy8qQIPDg6iv78fd/m85Q/Atn07
+ TEyDgDeyyhucTtjt9iFwEk/muzPPPYfk8eORSD1LzZg7D111dUpiYmK/YAuBUzJC/VeKFfuu3XAy9PUs
+ qBqqjfktnRUOx3vvoT8YxABJ3L59Wx293bduobO+Hq7iYjXcAmypqkKgowN/5ZpEpuZHgp8bOxYJ1HhN
+ UyZNgiMuDiaT6aFgCwGjzPGG2DilmuGqXRmJmpUrYGEKpKUqI5arobZx+vXReB/D2slnS0sLPF4vHB4P
+ qqurYTab4Q+Bk7x4nvLss0giaKKmQiR5wgQYGWnBFGwh4BePrL/9BrbVbCcN2LxsKcqWLkUJ28gYEYHC
+ 6VNRwmnXwlby+nxwuVxwMAI1BK+i5/5AAHcIfo6pC4GHVKIgKmSSxo3DBc4OwRRsIXBPTjT93r2wLF+u
+ gpctWYISDhIjwfXSx9OnI2/MGKTRmJ5RchK8zuEY9ry0rAx9NHiRLSthl3WpI1RIhJ4pJJH61lvqKSrY
+ KoH79+/DdPDgkMcCzOLT81nE3r7EkGUTPJ2bL06ejNrz51FNcJvNNgTOAjSx/QwkYeWwujR7tgok60Uz
+ HlUhMH8+BgYGhgn4gz1BVB79GgYS0Av44kXQsW0uEDhLA89j8dQSwOZ2w8o0mCsrUSoEKipgMhhQzGIs
+ Ki9HjU6Hgpkz1T2yV8jnjtALjFAuZ0Nfb+9wCozuRo9Sd+YMrpKAjM7C8HB1ozAWb3IJbs/Lg5Wht9Lz
+ SoL72fM3aKSQM75IIqDXy4UEFeyGBpMJujfeUAnka3pJdPRoFLAGDJ98Ag/vDYItBE6R/QPv1SsojFgG
+ 3dy5w+CSt6yXX4adp5mAW+h5BT0W8Js3biCJhJOnTYMuMwtGRkOiInXh4UzwW8womjFDBb1MvUK9Ss0c
+ Nx4NyUkKyQ4KthCIORt/tr/d7cJFFmD2Sy+p4RPPzzP/9szMIXCLRQX3aeChVhOSmWxTA9NT09iIRq71
+ sUv6/taPvro6GCdNhv6ZZ2CgGqnnp0xFd4ODgyhheBCpo7ijrU3J5ymXPnGiCi59m8ERamFuzTxYyplf
+ P+f8TVZ7PM8AqXYBDxXaBRZfNVMQ4NkR5NC6pyhqq8kMKSNw5ZjRKOMktJ44DrnefXnkyNAoFpGDQQ6I
+ hthYpDLfSTQuQ+PP1DR2g573g9bOThU8jnPiT3wvJIWAgEvKpGALXn8dLTwHHsjEZJSu8HQsYtiruaaG
+ tjJffBE+ox4G44jDSIRMho/jPN5qUl55BbHcICE+TU3m8Vt7+TJil0XgB/4vA0UISL9nUgVccl1ILWEN
+ BXJyYODFRUJfx7UO7rFNmIg8EnrscSwSupB0MdfnZoQhgfkXTwVQ9I/aU+a5pEcISPjFe6lyHcHFW8mz
+ PMv5FGD388+jjnWVNmUKgizQyzrdzy8kImQ0fCXzpKcjhRtiSeJ7DVjISERGElBzr3kvFS7gFfzNxt8E
+ vJHgDtpIf+01tGTnwOl0/usrmQhfDF9Km0gikSM4jm34PQ0JiZEE1BZ9xPtSahXX1FJd3GMneAbbtCU3
+ 9z9fSkPCBcPXckmHHBxnXn0VcSwgqXypjUcJSI9Lm5nHjEUNgW1cm/vCC8jnLSnIwfTE1/KQCEsJVejD
+ pJXtVfbFESROnYZY5jOFxtNJJoskLlEvU/UEzmObpRJct3s3r+I5asE99YdJSLhh+NOMk3JQrmzdHJ/X
+ CgqU6pMnlcJ9e5EesQQp4bORR09Nn30GNz/PunhQBeXTTK8flL1iQ2xpZp9euPn/83H6qNDY/+DzfNSo
+ fwDWYGmBKz70PQAAAABJRU5ErkJggg==
+
+
+
\ No newline at end of file
diff --git a/Navferty.Common/Extensions/ControlsExtensions.cs b/Navferty.Common/Extensions/ControlsExtensions.cs
index f237c66..a648a64 100644
--- a/Navferty.Common/Extensions/ControlsExtensions.cs
+++ b/Navferty.Common/Extensions/ControlsExtensions.cs
@@ -1,10 +1,11 @@
using System;
using System.Diagnostics;
using System.Drawing;
-using System.Drawing.Drawing2D;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
+using Navferty.Common.WinAPI;
+
#nullable enable
namespace Navferty.Common
@@ -16,9 +17,9 @@ public static class ControlsExtensions
public static void SetVistaCueBanner(this TextBox ctl, string? BannerText = null)
{
_ = ctl ?? throw new ArgumentNullException(nameof(ctl));
- ctl.RunWhenHandleReady(tb => WinAPI.SendMessage(
+ ctl.RunWhenHandleReady(tb => Windows.SendMessage(
tb.Handle,
- WinAPI.WindowMessages.EM_SETCUEBANNER,
+ Windows.WindowMessages.EM_SETCUEBANNER,
0,
BannerText));
}
@@ -75,6 +76,15 @@ public static void RunDelayed(this Action DelayedAction, int DelayInterval = 100
private const int DEFAULT_TEXT_EDIT_DELAY = 1000;
private const string DEFAULT_FILTER_CUEBANNER = "Filter";
+ ///
+ /// Attaches a deferred text change event handler that makes it possible to react to text changes with some delay,
+ /// allowing the user to correct erroneous input,
+ /// or complete input, rather than reacting immediately to each letter.
+ ///
+ /// TextChanged Handler
+ /// Delay (ms.) during which repeated input will not call the handler
+ /// Vista cueabanner text
+ /// Sets the background color for textbox to Systemcolors.Info
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void AttachDelayedFilter(
this TextBox txtCtl,
@@ -97,13 +107,13 @@ public static void AttachDelayedFilter(
};
txtCtl.TextChanged += (s, e) =>
{
- //Перезапускаем таймер
+ //Restart timer...
TMR.Stop();
TMR.Start();
};
}
-
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void AttachDelayedFilter(
this TextBox txtCtl,
@@ -120,28 +130,6 @@ public static void AttachDelayedFilter(
SetBackColorAsSystemTipColor);
}
-
- /*
-
-
- Friend Sub AttachDelayedFilter(TB As System.Windows.Forms.ToolStripTextBox,
- TextChangedCallBack As Action,
- Optional iDelay_ms As Integer = 1000,
- Optional VistaCueBanner As String = C_DEFAULT_FILTER_TEXTBOX_CUE_BANNER,
- Optional SetBackColorAsSystemTipColor As Boolean = True)
-
-
- With TB
-
- Call.TextBox.AttachDelayedFilter(TextChangedCallBack, iDelay_ms, VistaCueBanner, SetBackColorAsSystemTipColor)
-
- If(SetBackColorAsSystemTipColor) Then.BackColor = SystemColors.Info
- End With
- End Sub
- */
-
-
-
#endregion
}
diff --git a/Navferty.Common/Extensions/DelegatesExtensions.cs b/Navferty.Common/Extensions/DelegatesExtensions.cs
new file mode 100644
index 0000000..c5d603d
--- /dev/null
+++ b/Navferty.Common/Extensions/DelegatesExtensions.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+using NLog;
+
+#nullable enable
+
+namespace Navferty.Common
+{
+ [DebuggerStepThrough]
+ public static class DelegatesExtensions
+ {
+ public static bool TryCatch(
+ this Action a,
+ bool displayErrorMessage = true,
+ string? errorTitle = null,
+ ILogger? logger = null,
+ string? loggerTitle = null,
+ bool allowErrorReporting = true
+ )
+ {
+ try
+ {
+ a.Invoke();
+ return true;
+ }
+ catch (Exception ex)
+ {
+ errorTitle ??= Application.ProductName;
+ loggerTitle ??= errorTitle;
+
+ if (displayErrorMessage)
+ {
+ ex.ShowErrorUI(errorTitle, logger, loggerTitle, allowErrorReporting);
+ //MessageBox.Show(ex.Message, errorTitle!, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ else
+ {
+ logger?.Error(ex, loggerTitle);
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/Navferty.Common/Extensions/ErrorsExtensions.cs b/Navferty.Common/Extensions/ErrorsExtensions.cs
new file mode 100644
index 0000000..3b86c2f
--- /dev/null
+++ b/Navferty.Common/Extensions/ErrorsExtensions.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+using Navferty.Common.Controls;
+
+using NLog;
+
+#nullable enable
+
+namespace Navferty.Common
+{
+ [DebuggerStepThrough]
+ public static class ErrorsExtensions
+ {
+ /// Displays error message box to user, with ability to send feedback, and wites error to the Log
+ /// Some description about error to display to the user
+ ///
+ /// Some description about error to write to Log. If null - use errorTitle
+ /// Allow user to send bug report
+ public static void ShowErrorUI(
+ this Exception ex,
+ string? errorTitle = null,
+ ILogger? logger = null,
+ string? loggerTitle = null,
+ bool allowErrorReporting = true)
+ {
+ loggerTitle ??= errorTitle ?? "[Error description empty]";
+ logger ??= NLog.LogManager.GetCurrentClassLogger();
+ logger?.Error(ex, loggerTitle);
+
+ using var ef = new ErrorDialog(ex, errorTitle, allowErrorReporting);
+ ef.ShowDialog();
+ }
+ }
+}
diff --git a/Navferty.Common/Extensions/RangeExtensions.cs b/Navferty.Common/Extensions/RangeExtensions.cs
new file mode 100644
index 0000000..dbff9ab
--- /dev/null
+++ b/Navferty.Common/Extensions/RangeExtensions.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+using Microsoft.Office.Interop.Excel;
+
+namespace Navferty.Common
+{
+ [DebuggerStepThrough]
+ public static class RangeExtensions
+ {
+ public const Int64 DEFAULT_MAX_ALLOWED_CELLS = 1_000_000L;
+
+ public class TooManyCellsException : Exception
+ {
+ public TooManyCellsException() : base(Localization.UIStrings.Error_TooManyCellsSelected) { }
+ }
+
+ /// Throws error if cells count in specifed range more than 'maxAllowedCellsInRange' (DEFAULT_MAX_ALLOWED_CELLS_IN_RANGE)
+ ///
+ ///
+ ///
+
+ [DebuggerStepThrough]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Int64 ThrowIfTooManyCellsSelected(
+ this Range? sel,
+ Int64 maxAllowedCellsInRange = DEFAULT_MAX_ALLOWED_CELLS)
+ {
+ Int64 iCellsSelected = sel?.Cells?.Count ?? 0;
+
+ if (iCellsSelected > DEFAULT_MAX_ALLOWED_CELLS)
+ throw new TooManyCellsException();
+
+ return iCellsSelected;
+ }
+ }
+}
diff --git a/Navferty.Common/Extensions/StringExtensions.cs b/Navferty.Common/Extensions/StringExtensions.cs
index d63c277..5ad1199 100644
--- a/Navferty.Common/Extensions/StringExtensions.cs
+++ b/Navferty.Common/Extensions/StringExtensions.cs
@@ -1,5 +1,6 @@
using System.Linq;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
#nullable enable
@@ -32,5 +33,14 @@ public static int CountChars(this string value, char c)
{
return value.Count(x => x == c);
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static string LimitLength(
+ this string text,
+ int MaxLength)
+ {
+ if (text.Length > MaxLength) text = new string(text.Take(MaxLength).ToArray());
+ return text;
+ }
}
}
diff --git a/Navferty.Common/Feedback/FeedbackManager.cs b/Navferty.Common/Feedback/FeedbackManager.cs
new file mode 100644
index 0000000..1f14077
--- /dev/null
+++ b/Navferty.Common/Feedback/FeedbackManager.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Windows.Forms;
+
+using Microsoft.Win32;
+
+using Navferty.Common.WinAPI.Networking.Mail;
+
+using NLog;
+
+#nullable enable
+
+namespace Navferty.Common.Feedback
+{
+ public static class FeedbackManager
+ {
+ private const string GITHUB_BUGTRACKER_URL = @"https://github.com/navferty/NavfertyExcelAddIn/issues";
+ private const string DEVELOPER_MAIL = @"navferty@ymail.com";
+ private const string MAIL_SUBJECT = @"NavfertyExcelAddin Bug report from user!";
+ internal const int MAX_USER_TEXT_LENGH = 1_000;
+
+ private static FileInfo[] GetScreenshotsAsFiles(ImageFormat fmt, string fileExt = "jpg")
+ => System.Windows.Forms.Screen.AllScreens.ToList().Select(scr =>
+ {
+ using (Bitmap bmCapt = new(scr.Bounds.Width, scr.Bounds.Height, PixelFormat.Format32bppArgb))
+ {
+ var rcCapt = scr.Bounds;
+ using (Graphics g = Graphics.FromImage(bmCapt))
+ g.CopyFromScreen(rcCapt.Left, rcCapt.Top, 0, 0, rcCapt.Size);
+
+ var sBitmapFile = Path.Combine(Path.GetTempPath(), (Guid.NewGuid().ToString() + '.'.ToString() + fileExt));
+ bmCapt.Save(sBitmapFile, fmt);
+ return new System.IO.FileInfo(sBitmapFile);
+ }
+ }).ToArray();
+
+ /// This used for debug!
+ //If you want to send error reports to custom email,
+ //create new string value 'Navferty_ExcelAddIn_Feedback_Email' in root of 'HKEY_CURRENT_USER' and set you mail
+ ///
+ internal static string GetDeveloperMail()
+ {
+ try
+ {
+ string mail = Registry.CurrentUser.GetValue("Navferty_ExcelAddIn_Feedback_Email").ToString().Trim();
+ if (string.IsNullOrWhiteSpace(mail)) mail = DEVELOPER_MAIL;
+ return mail;
+ }
+ catch { return DEVELOPER_MAIL; }
+ }
+
+ /// Create and Send feedback mail using MAPI.
+ ///
+ /// In fact, the email is not sent immediately, but is cached in the mail client,
+ /// and will be sent when the user launches the mail client.
+ /// If the mail client is already running, the email will be sent at the next synchronization.
+ ///
+ /// Some mail body text
+ /// Takes and sends Screenshots of each monitor
+ /// This window will be hidden to take screenshots
+ internal static bool SendFeedbackMail(
+ string userText,
+ bool sendScreenshots = true,
+ Form? parentWindow = null
+ )
+ {
+
+ var logger = LogManager.GetCurrentClassLogger();
+ logger.Debug("Start SendFeedEMail Task...");
+
+ string developerMail = GetDeveloperMail();
+ logger.Debug($"developerMail: '{developerMail}'");
+
+ List lFilesToAttach = new();
+ userText = userText.LimitLength(MAX_USER_TEXT_LENGH);
+
+ string sysInfo = GetSystemInfo().Trim();
+ logger.Debug($"System Info Dump:\n{sysInfo}\n\n********\nUser message: '{userText}'\n");
+
+ StringBuilder sbMessageBody = new();
+ sbMessageBody.Append("User message: ");
+ sbMessageBody.AppendLine((string.IsNullOrWhiteSpace(userText) ? "[NONE]" : ('"' + userText + '"')));
+ string messageBody = sbMessageBody.ToString();
+
+ if (sendScreenshots)
+ {
+ if (parentWindow != null)
+ {
+ //Temporary hide feedback UI to make clear screenshots
+ parentWindow.Opacity = 0;
+ parentWindow.Refresh();
+ Application.DoEvents();
+ }
+ try
+ {
+ //Create screenshots to temp dir
+ var screenshotFiles = GetScreenshotsAsFiles(ImageFormat.Jpeg);
+ lFilesToAttach.AddRange(screenshotFiles);
+ string screenshotFileNames = string.Join(", ", screenshotFiles.Select(fi => fi.FullName));
+ logger.Debug($"Screenshot Files ({lFilesToAttach.Count}): '{screenshotFileNames}'");
+ }
+ finally
+ {
+ if (parentWindow != null)
+ {
+ //Restore feedback UI
+ parentWindow.Opacity = 1;
+ parentWindow.Refresh();
+ Application.DoEvents();
+ }
+ }
+ }
+
+ var fiNLogFile = GetNLogFile();
+ if (null != fiNLogFile && fiNLogFile.Exists)
+ {
+ logger.Debug($"Log File Found: '{fiNLogFile.FullName}', Exist: {fiNLogFile.Exists}");
+ FileInfo fiLogFileInTempDir = new(Path.Combine(
+ Path.GetTempPath(),
+ (Guid.NewGuid().ToString() + "_" + fiNLogFile.Name)));
+
+ //Drop last NLog cache data to disk
+ {
+ //logger.Factory.Flush();
+ LogManager.Flush();
+ Thread.Sleep(1000); //Waiting NLog flush task to finish
+ }
+
+ //Copy NLog file to temp file
+ fiNLogFile.CopyTo(fiLogFileInTempDir.FullName);
+
+ //Attach temp NLog file to email
+ if (fiLogFileInTempDir.Exists) lFilesToAttach.Add(fiLogFileInTempDir);
+ }
+
+ logger.Debug($"Total Files To Attach: '{lFilesToAttach.Count}'");
+ try
+ {
+ //Send mail
+ var bSend = MAPI.SendMail(
+ developerMail,
+ MAIL_SUBJECT,
+ messageBody,
+ MAPI.UIFlags.SendMailDirectNoUI,
+ parentWindow,
+ lFilesToAttach.Select(fi => fi.FullName).ToArray()
+ );
+
+ logger.Debug($"Send result: {bSend}");
+ return bSend;
+ }
+ finally
+ {
+ //Cleanup Temp files
+ lFilesToAttach.ForEach(fi =>
+ {
+ try { fi.Delete(); }
+ catch { }
+ });
+ }
+ }
+
+ /// Collect some debug information about system to help resolve errors
+ private static string GetSystemInfo()
+ {
+ Func DumpAssemmbly = new((asm, title) =>
+ {
+ StringBuilder sbAsm = new();
+ sbAsm.AppendLine($"*** {title ?? string.Empty} Assembly '{asm.FullName}'");
+ sbAsm.AppendLine($"Location: '{asm.Location}'");
+ sbAsm.AppendLine($"ImageRuntimeVersion: '{asm.ImageRuntimeVersion}'");
+ sbAsm.AppendLine($"Trusted: '{asm.IsFullyTrusted}'");
+ sbAsm.AppendLine($"EntryPoint: '{asm.EntryPoint}'");
+ return sbAsm.ToString();
+ });
+
+ Func DumpAssemmblyName = new((asmn, title) =>
+ {
+ StringBuilder sbAsm = new();
+ sbAsm.AppendLine($"*** {title ?? string.Empty} Assembly '{asmn.FullName}'");
+ sbAsm.AppendLine($"CodeBase: '{asmn.CodeBase}'");
+ sbAsm.AppendLine($"ContentType: '{asmn.ContentType}'");
+ sbAsm.AppendLine($"Culture: '{asmn.CultureInfo.DisplayName}'");
+ sbAsm.AppendLine($"ProcessorArchitecture: '{asmn.ProcessorArchitecture}'");
+ return sbAsm.ToString();
+ });
+
+ var dtNow = DateTime.Now;
+ var asm = Assembly.GetExecutingAssembly();
+ StringBuilder sbSysInfo = new();
+ sbSysInfo.AppendLine("*** Product:");
+ sbSysInfo.AppendLine($"Name: '{Application.ProductName}' v'{Application.ProductVersion}'");
+ sbSysInfo.AppendLine($"Path: '{Application.ExecutablePath}'");
+ sbSysInfo.AppendLine();
+ sbSysInfo.AppendLine(DumpAssemmbly(Assembly.GetExecutingAssembly(), "Executing"));
+ sbSysInfo.AppendLine(DumpAssemmbly(Assembly.GetCallingAssembly(), "Calling"));
+
+ Assembly.GetExecutingAssembly()
+ .GetReferencedAssemblies()
+ .OrderBy(asmn => asmn.FullName)
+ .ToList()
+ .ForEach(asmn => { sbSysInfo.AppendLine(DumpAssemmblyName(asmn, "Referenced")); });
+
+ sbSysInfo.AppendLine("*** TimeZone:");
+ sbSysInfo.AppendLine(dtNow.Kind.ToString() + $": {dtNow}");
+ sbSysInfo.AppendLine($"Utc: {dtNow.ToUniversalTime()}");
+ sbSysInfo.AppendLine($"UtcOffset: {TimeZone.CurrentTimeZone.GetUtcOffset(dtNow)}");
+ sbSysInfo.AppendLine();
+ sbSysInfo.AppendLine("*** Culture:");
+ sbSysInfo.AppendLine($"CultureInfo.CurrentCulture: {CultureInfo.CurrentCulture}");
+ sbSysInfo.AppendLine($"CultureInfo.CurrentUICulture: {CultureInfo.CurrentUICulture}");
+ sbSysInfo.AppendLine($"Application.CurrentCulture: {Application.CurrentCulture}");
+ sbSysInfo.AppendLine($"InputLanguage: {Application.CurrentInputLanguage.Culture} (Layout: {Application.CurrentInputLanguage.LayoutName})");
+ sbSysInfo.AppendLine();
+ sbSysInfo.AppendLine($"VisualStyleState: {Application.VisualStyleState}");
+ return sbSysInfo.ToString();
+ }
+
+ /// Return NLog engine Log file path on the disk
+ private static FileInfo? GetNLogFile()
+ {
+ LogManager.Flush(); //Write NLog cache to disk if this still in RAM
+ var logFileName = LogManagement.GetTargetFilename(null);
+ if (logFileName != null) return new(logFileName);
+ return null;
+ }
+
+ /// Displays user Feedback UI dialog
+ /// some text to prefill user comment textbox
+ public static void ShowFeedbackUI(string? message = null)
+ {
+ using var fui = new frmFeedbackUI(message);
+ fui.ShowDialog();
+ }
+
+ /// Opens Github issues page in Web browser
+ public static void ShowGithub()
+ => System.Diagnostics.Process.Start(GITHUB_BUGTRACKER_URL);
+
+ /// Opens NLog engine file in text editor
+ public static void ShowLogFile()
+ => System.Diagnostics.Process.Start(GetNLogFile()!.FullName);
+
+ }
+}
diff --git a/Navferty.Common/Feedback/frmFeedbackUI.Designer.cs b/Navferty.Common/Feedback/frmFeedbackUI.Designer.cs
new file mode 100644
index 0000000..2fea728
--- /dev/null
+++ b/Navferty.Common/Feedback/frmFeedbackUI.Designer.cs
@@ -0,0 +1,167 @@
+namespace Navferty.Common.Feedback
+{
+ partial class frmFeedbackUI
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(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()
+ {
+ this.btnSend = new System.Windows.Forms.Button();
+ this.lblMessage = new System.Windows.Forms.Label();
+ this.chkIncludeScreenshots = new System.Windows.Forms.CheckBox();
+ this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
+ this.txtUserMessage = new System.Windows.Forms.TextBox();
+ this.lblSummary = new System.Windows.Forms.LinkLabel();
+ this.llGotoGithub = new System.Windows.Forms.LinkLabel();
+ this.tableLayoutPanel1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // btnSend
+ //
+ this.btnSend.Dock = System.Windows.Forms.DockStyle.Right;
+ this.btnSend.Location = new System.Drawing.Point(428, 231);
+ this.btnSend.Name = "btnSend";
+ this.tableLayoutPanel1.SetRowSpan(this.btnSend, 2);
+ this.btnSend.Size = new System.Drawing.Size(113, 34);
+ this.btnSend.TabIndex = 1;
+ this.btnSend.Text = "Send";
+ this.btnSend.UseVisualStyleBackColor = true;
+ this.btnSend.Click += new System.EventHandler(this.OnSend);
+ //
+ // lblMessage
+ //
+ this.lblMessage.AutoSize = true;
+ this.tableLayoutPanel1.SetColumnSpan(this.lblMessage, 2);
+ this.lblMessage.Dock = System.Windows.Forms.DockStyle.Top;
+ this.lblMessage.Location = new System.Drawing.Point(7, 4);
+ this.lblMessage.Name = "lblMessage";
+ this.lblMessage.Size = new System.Drawing.Size(534, 13);
+ this.lblMessage.TabIndex = 1;
+ this.lblMessage.Text = "message";
+ //
+ // chkIncludeScreenshots
+ //
+ this.chkIncludeScreenshots.AutoSize = true;
+ this.tableLayoutPanel1.SetColumnSpan(this.chkIncludeScreenshots, 2);
+ this.chkIncludeScreenshots.Dock = System.Windows.Forms.DockStyle.Top;
+ this.chkIncludeScreenshots.Location = new System.Drawing.Point(7, 208);
+ this.chkIncludeScreenshots.Name = "chkIncludeScreenshots";
+ this.chkIncludeScreenshots.Size = new System.Drawing.Size(534, 17);
+ this.chkIncludeScreenshots.TabIndex = 2;
+ this.chkIncludeScreenshots.Text = "include screenshot";
+ this.chkIncludeScreenshots.UseVisualStyleBackColor = true;
+ //
+ // tableLayoutPanel1
+ //
+ this.tableLayoutPanel1.ColumnCount = 2;
+ this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
+ this.tableLayoutPanel1.Controls.Add(this.btnSend, 1, 3);
+ this.tableLayoutPanel1.Controls.Add(this.lblMessage, 0, 0);
+ this.tableLayoutPanel1.Controls.Add(this.txtUserMessage, 0, 1);
+ this.tableLayoutPanel1.Controls.Add(this.chkIncludeScreenshots, 0, 2);
+ this.tableLayoutPanel1.Controls.Add(this.lblSummary, 0, 3);
+ this.tableLayoutPanel1.Controls.Add(this.llGotoGithub, 0, 4);
+ this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.tableLayoutPanel1.Location = new System.Drawing.Point(8, 8);
+ this.tableLayoutPanel1.Name = "tableLayoutPanel1";
+ this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(4);
+ this.tableLayoutPanel1.RowCount = 5;
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+ this.tableLayoutPanel1.Size = new System.Drawing.Size(548, 272);
+ this.tableLayoutPanel1.TabIndex = 0;
+ //
+ // txtUserMessage
+ //
+ this.tableLayoutPanel1.SetColumnSpan(this.txtUserMessage, 2);
+ this.txtUserMessage.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.txtUserMessage.HideSelection = false;
+ this.txtUserMessage.Location = new System.Drawing.Point(7, 20);
+ this.txtUserMessage.MaxLength = 1000;
+ this.txtUserMessage.Multiline = true;
+ this.txtUserMessage.Name = "txtUserMessage";
+ this.txtUserMessage.ScrollBars = System.Windows.Forms.ScrollBars.Both;
+ this.txtUserMessage.Size = new System.Drawing.Size(534, 182);
+ this.txtUserMessage.TabIndex = 0;
+ //
+ // lblSummary
+ //
+ this.lblSummary.AutoSize = true;
+ this.lblSummary.Dock = System.Windows.Forms.DockStyle.Top;
+ this.lblSummary.Location = new System.Drawing.Point(7, 228);
+ this.lblSummary.Name = "lblSummary";
+ this.lblSummary.Size = new System.Drawing.Size(415, 13);
+ this.lblSummary.TabIndex = 4;
+ this.lblSummary.TabStop = true;
+ this.lblSummary.Text = "summary";
+ //
+ // llGotoGithub
+ //
+ this.llGotoGithub.AutoSize = true;
+ this.llGotoGithub.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.llGotoGithub.Location = new System.Drawing.Point(7, 255);
+ this.llGotoGithub.Name = "llGotoGithub";
+ this.llGotoGithub.Size = new System.Drawing.Size(415, 13);
+ this.llGotoGithub.TabIndex = 2;
+ this.llGotoGithub.TabStop = true;
+ this.llGotoGithub.Text = "goto github";
+ this.llGotoGithub.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnGotoGithub);
+ //
+ // frmFeedbackUI
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(564, 288);
+ this.Controls.Add(this.tableLayoutPanel1);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "frmFeedbackUI";
+ this.Padding = new System.Windows.Forms.Padding(8);
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "frmFeedbackUI";
+ this.tableLayoutPanel1.ResumeLayout(false);
+ this.tableLayoutPanel1.PerformLayout();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Button btnSend;
+ private System.Windows.Forms.Label lblMessage;
+ private System.Windows.Forms.CheckBox chkIncludeScreenshots;
+ private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
+ private System.Windows.Forms.TextBox txtUserMessage;
+ private System.Windows.Forms.LinkLabel lblSummary;
+ private System.Windows.Forms.LinkLabel llGotoGithub;
+ }
+}
diff --git a/Navferty.Common/Feedback/frmFeedbackUI.cs b/Navferty.Common/Feedback/frmFeedbackUI.cs
new file mode 100644
index 0000000..9a1c92d
--- /dev/null
+++ b/Navferty.Common/Feedback/frmFeedbackUI.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Windows.Forms;
+
+using Navferty.Common.Controls;
+//using Navferty.Common.DelegatesExtensions;
+
+using NLog;
+
+#nullable enable
+
+namespace Navferty.Common.Feedback
+{
+ internal partial class frmFeedbackUI : FormEx
+ {
+ private readonly ILogger logger = LogManager.GetCurrentClassLogger();
+
+ [Obsolete("Just for Designer!", true)]
+ public frmFeedbackUI() : base()
+ {
+ InitializeComponent();
+ }
+
+ public frmFeedbackUI(string? message = null) : base()
+ {
+ InitializeComponent();
+
+ Text = Localization.UIStrings.Feedback_Title;
+ lblMessage.Text = String.Format(Localization.UIStrings.Feedback_Message, FeedbackManager.MAX_USER_TEXT_LENGH);
+ txtUserMessage.MaxLength = FeedbackManager.MAX_USER_TEXT_LENGH;
+
+ if (!string.IsNullOrWhiteSpace(message))
+ {
+ message = message!.LimitLength(FeedbackManager.MAX_USER_TEXT_LENGH);
+ txtUserMessage.Text = message;
+ }
+
+
+ chkIncludeScreenshots.Text = Localization.UIStrings.Feedback_IncludeScreenshots;
+ chkIncludeScreenshots.Checked = true;
+
+ llGotoGithub.Text = Localization.UIStrings.Feedback_GotoGithub;
+ btnSend.Text = Localization.UIStrings.Feedback_Send;
+
+ //Create ink to show NLog Log file
+ {
+ string fullSummaryText = string.Format(Localization.UIStrings.Feedback_Summary_Template, Localization.UIStrings.Feedback_Summary_Loglink);
+ lblSummary.Text = fullSummaryText;
+ var la = new LinkArea(fullSummaryText.IndexOf(Localization.UIStrings.Feedback_Summary_Loglink), Localization.UIStrings.Feedback_Summary_Loglink.Length);
+ lblSummary.LinkArea = la;
+ lblSummary.LinkClicked += (s, e) => OnShowLog();
+ }
+ }
+
+ private void OnSend(object sender, EventArgs e)
+ {
+ new Action(() =>
+ {
+ if (FeedbackManager.SendFeedbackMail(
+ txtUserMessage.Text.Trim(),
+ chkIncludeScreenshots.Checked,
+ this))
+
+ DialogResult = DialogResult.OK;
+
+ }).TryCatch(true,
+ Localization.UIStrings.Feedback_ErrorTitle,
+ logger, "Failed to send feedback mail!");
+ }
+
+
+ private void OnGotoGithub(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ new Action(() => { FeedbackManager.ShowGithub(); })
+ .TryCatch(true,
+ Localization.UIStrings.Feedback_ErrorTitle,
+ logger, "Failed to open Github bugtracker!");
+ }
+ private void OnShowLog()
+ {
+
+ new Action(() =>
+ {
+ /*
+ var EEE = new Exception("Test");
+ throw EEE;
+ */
+ FeedbackManager.ShowLogFile();
+ })
+ .TryCatch(true,
+ Localization.UIStrings.Feedback_ErrorTitle,
+ logger, "Failed to show NLog log file!");
+
+ }
+ }
+}
diff --git a/Navferty.Common/Feedback/frmFeedbackUI.resx b/Navferty.Common/Feedback/frmFeedbackUI.resx
new file mode 100644
index 0000000..29dcb1b
--- /dev/null
+++ b/Navferty.Common/Feedback/frmFeedbackUI.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Navferty.Common/Interfaces/IDialogService.cs b/Navferty.Common/Interfaces/IDialogService.cs
index d755c89..cb731b2 100644
--- a/Navferty.Common/Interfaces/IDialogService.cs
+++ b/Navferty.Common/Interfaces/IDialogService.cs
@@ -1,4 +1,7 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+
+using NLog;
#nullable enable
@@ -6,7 +9,9 @@ namespace Navferty.Common
{
public interface IDialogService
{
+ [Obsolete("Use ShowError(Exception, ILogger) instead", true)]
void ShowError(string message);
+ void ShowError(Exception e, ILogger? logger = null);
void ShowInfo(string message);
bool Ask(string message, string caption);
void ShowVersion();
diff --git a/Navferty.Common/Localization/UIStrings.Designer.cs b/Navferty.Common/Localization/UIStrings.Designer.cs
new file mode 100644
index 0000000..fa82011
--- /dev/null
+++ b/Navferty.Common/Localization/UIStrings.Designer.cs
@@ -0,0 +1,180 @@
+//------------------------------------------------------------------------------
+//
+// 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 Navferty.Common.Localization {
+ 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", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class UIStrings {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal UIStrings() {
+ }
+
+ ///
+ /// 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("Navferty.Common.Localization.UIStrings", typeof(UIStrings).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 Too many cells selected!.
+ ///
+ internal static string Error_TooManyCellsSelected {
+ get {
+ return ResourceManager.GetString("Error_TooManyCellsSelected", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Close.
+ ///
+ internal static string ErrorWindow_OkButton {
+ get {
+ return ResourceManager.GetString("ErrorWindow_OkButton", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to An error has occurred!.
+ ///
+ internal static string ErrorWindow_Title {
+ get {
+ return ResourceManager.GetString("ErrorWindow_Title", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Error!.
+ ///
+ internal static string Feedback_Error {
+ get {
+ return ResourceManager.GetString("Feedback_Error", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Failed to send feedback email!.
+ ///
+ internal static string Feedback_ErrorTitle {
+ get {
+ return ResourceManager.GetString("Feedback_ErrorTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bug tracker and feature request.
+ ///
+ internal static string Feedback_GotoGithub {
+ get {
+ return ResourceManager.GetString("Feedback_GotoGithub", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Include screenshot.
+ ///
+ internal static string Feedback_IncludeScreenshots {
+ get {
+ return ResourceManager.GetString("Feedback_IncludeScreenshots", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Briefly describe the error that occurs (no more than {0} characters):.
+ ///
+ internal static string Feedback_Message {
+ get {
+ return ResourceManager.GetString("Feedback_Message", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Send.
+ ///
+ internal static string Feedback_Send {
+ get {
+ return ResourceManager.GetString("Feedback_Send", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Send Feedback.
+ ///
+ internal static string Feedback_SendFeedback {
+ get {
+ return ResourceManager.GetString("Feedback_SendFeedback", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to an error log.
+ ///
+ internal static string Feedback_Summary_Loglink {
+ get {
+ return ResourceManager.GetString("Feedback_Summary_Loglink", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The report will include {0}..
+ ///
+ internal static string Feedback_Summary_Template {
+ get {
+ return ResourceManager.GetString("Feedback_Summary_Template", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Feedback.
+ ///
+ internal static string Feedback_Title {
+ get {
+ return ResourceManager.GetString("Feedback_Title", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Navferty.Common/Localization/UIStrings.resx b/Navferty.Common/Localization/UIStrings.resx
new file mode 100644
index 0000000..de6f28d
--- /dev/null
+++ b/Navferty.Common/Localization/UIStrings.resx
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Close
+
+
+ An error has occurred!
+
+
+ Too many cells selected!
+
+
+ Error!
+
+
+ Failed to send feedback email!
+
+
+ Bug tracker and feature request
+
+
+ Include screenshot
+
+
+ Briefly describe the error that occurs (no more than {0} characters):
+
+
+ Send
+
+
+ Send Feedback
+
+
+ an error log
+
+
+ The report will include {0}.
+
+
+ Feedback
+
+
\ No newline at end of file
diff --git a/Navferty.Common/Localization/UIStrings.ru-RU.resx b/Navferty.Common/Localization/UIStrings.ru-RU.resx
new file mode 100644
index 0000000..8704f1e
--- /dev/null
+++ b/Navferty.Common/Localization/UIStrings.ru-RU.resx
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Закрыть
+
+
+ Произошла ошибка!
+
+
+ Выбрано слишком много ячеек!
+
+
+ Ошибка!
+
+
+ Не удалось отправить отчёт разработчику!
+
+
+ Трекер ошибок и запроса новых функций
+
+
+ Приложить скриншот
+
+
+ Кратко опишите возникающую ошибку (не более {0} символов):
+
+
+ Отправить
+
+
+ Сообщить разработчикам
+
+
+ журнал ошибок
+
+
+ Отчёт будет включать в себя {0}.
+
+
+ Обратная связь
+
+
\ No newline at end of file
diff --git a/Navferty.Common/LogManagement.cs b/Navferty.Common/LogManagement.cs
new file mode 100644
index 0000000..45df900
--- /dev/null
+++ b/Navferty.Common/LogManagement.cs
@@ -0,0 +1,73 @@
+
+using System.Linq;
+
+using NLog;
+using NLog.Layouts;
+using NLog.Targets;
+
+#nullable enable
+
+namespace Navferty.Common
+{
+ internal static class LogManagement
+ {
+ //private const string DefaultTargetName = "AllTargets";
+
+ public static string? GetTargetFilename(string? targetName)
+ {
+ FileTarget? target = null;
+ if (string.IsNullOrWhiteSpace(targetName))
+ {
+ var fileTargets = GetFileTargets();
+ target = fileTargets.FirstOrDefault();
+ }
+ else
+ {
+ target = GetTarget(targetName!);
+ }
+ if (null == target) return null;
+
+ var layout = target.FileName as SimpleLayout;
+ if (null == layout) return null;
+
+ // layout.Text provides the filename "template"
+ // LogEventInfo is required; might make sense for a log line template but not really filename
+ //var filename = layout.Render(new LogEventInfo()).Replace(@"/", @"");
+ var filename = layout.Render(new LogEventInfo()).Replace(@"/", @"\").Replace(@"\\", @"\"); ;
+ return filename;
+ }
+
+ private static T? GetTarget(string targetName)
+ where T : Target
+ {
+ if (null == LogManager.Configuration) return null;
+ var target = LogManager.Configuration.FindTargetByName(targetName) as T;
+ return target;
+ }
+
+ private static T[]? GetTargets()
+ where T : Target
+ {
+ if (null == LogManager.Configuration) return null;
+
+ var targets = LogManager.Configuration.AllTargets?.Where(trg => trg.GetType() == typeof(T)).ToArray();
+ return (T[]?)targets;
+ }
+ private static FileTarget[]? GetFileTargets()
+ {
+ if (null == LogManager.Configuration) return null;
+
+ var targets = LogManager.Configuration.AllTargets?
+ .Select(trg =>
+ {
+ FileTarget? ft = null;
+ if (trg is FileTarget ft2) ft = ft2;
+ return ft;
+ })
+ .Where(ft => ft != null)
+ .Select(ft => (FileTarget)ft!)
+ .ToArray();
+ return targets;
+ }
+ }
+}
diff --git a/Navferty.Common/Navferty.Common.csproj b/Navferty.Common/Navferty.Common.csproj
index b7c906c..ade78cc 100644
--- a/Navferty.Common/Navferty.Common.csproj
+++ b/Navferty.Common/Navferty.Common.csproj
@@ -41,6 +41,9 @@
Component
+
+ Form
+
Component
@@ -50,24 +53,81 @@
Form
+
+
+
+
+ UIStrings.resx
+ True
+ True
+
+
+
+
+ Form
+
+
+ frmFeedbackUI.cs
+
-
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+
+
+ True
+
+
+ ..\packages\NLog.4.6.7\lib\net45\NLog.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ErrorDialog.cs
+
+
+ frmFeedbackUI.cs
+
+
+ ResXFileCodeGenerator
+ UIStrings.Designer.cs
+ Designer
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
-
diff --git a/Navferty.Common/Properties/Resources.Designer.cs b/Navferty.Common/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..ed15fa3
--- /dev/null
+++ b/Navferty.Common/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// 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 Navferty.Common.Properties {
+ 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", "17.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() {
+ }
+
+ ///
+ /// 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("Navferty.Common.Properties.Resources", typeof(Resources).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;
+ }
+ }
+ }
+}
diff --git a/Navferty.Common/Properties/Resources.resx b/Navferty.Common/Properties/Resources.resx
new file mode 100644
index 0000000..29dcb1b
--- /dev/null
+++ b/Navferty.Common/Properties/Resources.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Navferty.Common/WinAPI/WinAPI.Core.cs b/Navferty.Common/WinAPI/WinAPI.Core.cs
new file mode 100644
index 0000000..7912012
--- /dev/null
+++ b/Navferty.Common/WinAPI/WinAPI.Core.cs
@@ -0,0 +1,21 @@
+#nullable enable
+
+#region Structures to interoperate with the Windows API
+
+using word = System.UInt16;
+using dword = System.UInt32;
+using hwnd = System.IntPtr;
+using large_int = System.Int64;
+using ulong_ptr = System.IntPtr;
+
+#endregion
+
+namespace Navferty.Common.WinAPI
+{
+
+ internal static class Core
+ {
+ public const string WINDLL_USER = "user32.dll";
+ }
+
+}
diff --git a/Navferty.Common/WinAPI/WinAPI.GDI.cs b/Navferty.Common/WinAPI/WinAPI.GDI.cs
new file mode 100644
index 0000000..c7322b5
--- /dev/null
+++ b/Navferty.Common/WinAPI/WinAPI.GDI.cs
@@ -0,0 +1,58 @@
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+
+using Microsoft.Win32.SafeHandles;
+
+#region Structures to interoperate with the Windows API
+
+using word = System.UInt16;
+using dword = System.UInt32;
+using hwnd = System.IntPtr;
+using large_int = System.Int64;
+using ulong_ptr = System.IntPtr;
+
+#endregion
+
+#nullable enable
+
+namespace Navferty.Common.WinAPI.GDI
+{
+ internal class DC : SafeHandleZeroOrMinusOneIsInvalid
+ {
+ [DllImport(Core.WINDLL_USER)]
+ private static extern IntPtr GetDC(hwnd hwnd);
+
+ [DllImport(Core.WINDLL_USER)]
+ private static extern bool ReleaseDC(hwnd hwnd, IntPtr hdc);
+
+ internal hwnd hWnd = IntPtr.Zero;
+
+ public DC(hwnd WindowHandle) : base(true)
+ {
+ var hdc = GetDC(WindowHandle);
+ if (hdc == IntPtr.Zero) throw new Win32Exception();
+ hWnd = WindowHandle;
+ SetHandle(hdc);
+ }
+
+ public DC(IWin32Window Window) : this(Window.Handle) { }
+
+ protected override bool ReleaseHandle()
+ {
+ if (IsInvalid) return true;
+ bool bResult = ReleaseDC(hWnd, handle);
+ SetHandle(IntPtr.Zero);
+ return bResult;
+ }
+
+ public Graphics CreateGraphics() => Graphics.FromHdc(DangerousGetHandle());
+ }
+
+ internal static class WinAPI_Extensions
+ {
+ public static DC GetDC(this IWin32Window wnd) => new(wnd.Handle);
+ }
+}
diff --git a/Navferty.Common/WinAPI/WinAPI.Networking.Mail.MAPI.cs b/Navferty.Common/WinAPI/WinAPI.Networking.Mail.MAPI.cs
new file mode 100644
index 0000000..6cdeb4c
--- /dev/null
+++ b/Navferty.Common/WinAPI/WinAPI.Networking.Mail.MAPI.cs
@@ -0,0 +1,357 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+
+#nullable enable
+
+namespace Navferty.Common.WinAPI.Networking.Mail
+{
+ ///
+ /// https://docs.microsoft.com/ru-ru/previous-versions/windows/desktop/windowsmapi/mapi32-dll-stub-registry-settings?redirectedfrom=MSDN
+ ///
+ internal static class MAPI
+ {
+ public const int MAX_ATTACHMENTS = 20;
+
+ public enum MAPI_ERRORS : int
+ {
+ [Description("OK")]
+ OK = 0,
+
+ [Description("User abort")]
+ UserAbort = 1,
+
+ [Description("General MAPI failure")]
+ GeneralMAPIFailure = 2,
+
+ [Description("MAPI login failure")]
+ MAPILoginFailure = 3,
+
+ [Description("Disk full")]
+ DiskFull = 4,
+
+ [Description("Insufficient memory")]
+ InsufficientMemory = 5,
+
+ [Description("Access denied [6")]
+ AccessDenied = 6,
+
+ [Description("Unknown")]
+ Unknown = 7,
+
+ [Description("Too many sessions")]
+ TooManySessions = 8,
+
+ [Description("Too many files were specified")]
+ TooManyFilesWereSpecified = 9,
+
+ [Description("Too many recipients were specified")]
+ ToomanyRecipientsWereSpecified = 10,
+
+ [Description("A specified attachment was not found")]
+ SpecifiedAttachmentWasNotFound = 11,
+
+ [Description("Attachment open failure")]
+ AttachmentOpenFailure = 12,
+
+ [Description("Attachment write failure")]
+ AttachmentWriteFailure = 13,
+
+ [Description("Unknown recipient")]
+ UnknownRecipient = 14,
+
+ [Description("Bad recipient type")]
+ BadRecipientType = 15,
+
+ [Description("No messages")]
+ NoMessages = 16,
+
+ [Description("Invalid message")]
+ InvalidMessage = 17,
+
+ [Description("Text too large")]
+ TextTooLarge = 18,
+
+ [Description("Invalid session")]
+ InvalidSession = 19,
+
+ [Description("Type not supported")]
+ TypeNotSupported = 20,
+
+ [Description("A recipient was specified ambiguously")]
+ RecipientWasSpecifiedAmbiguously = 21,
+
+ [Description("Message in use")]
+ MessageInUse = 22,
+
+ [Description("Network failure")]
+ NetworkFailure = 23,
+
+ [Description("Invalid edit fields")]
+ InvalidEditFields = 24,
+
+ [Description("Invalid recipients")]
+ InvalidRecipients = 25,
+
+ [Description("Not supported")]
+ NotSupported = 26,
+
+ //[EditorBrowsable(EditorBrowsableState.Never)]
+ Last
+ }
+
+ public class MAPIException : System.Exception
+ {
+ public readonly MAPI_ERRORS ErrorCode = MAPI_ERRORS.OK;
+ internal MAPIException(MAPI_ERRORS err) : base(GetErrorMessageForCode(err))
+ {
+ ErrorCode = err;
+ }
+ public override string Message => GetErrorMessageForCode(ErrorCode);
+
+ public static string GetErrorMessageForCode(MAPI_ERRORS Err)
+ {
+ if (Err >= MAPI_ERRORS.Last) return $"MAPI Error {Err}";
+ return Err.ToString();
+ }
+ }
+
+ public enum SendToFlags : int
+ {
+ MAPI_ORIG = 0,
+ MAPI_TO,
+ MAPI_CC,
+ MAPI_BCC
+ };
+
+ public enum UIFlags : uint
+ {
+ /// Display Send Mail UI dialog
+ PopupUI = 0,
+
+ /// Send mail without displaying the mail UI dialog.
+ /// for safety reason, MSOutlook displays warning UI that allows user to allow or block sending this mail (mail message itself is not visible to user)
+ SendMailDirectNoUI
+ }
+
+ #region API
+
+ private enum MAPI_FLAGS : uint
+ {
+ MAPI_LOGON_UI = 1, // Показать интерфейс входа в систему
+ MAPI_NEW_SESSION = 2, // Не использовать общий сеанс
+ MAPI_DIALOG = 8,
+ //MAPI_ALLOW_OTHERS = 8; исходное шестнадцатеричное значение 0x00000008 ; Сделать это общим сеансом
+ MAPI_EXPLICIT_PROFILE = 16, //Не использовать профиль по умолчанию
+ MAPI_EXTENDED = 32, //Расширенный вход MAPI
+ MAPI_FORCE_DOWNLOAD = 4096, //Получить новую почту перед возвратом
+ MAPI_SERVICE_UI_ALWAYS = 8192, //Выполнить вход в систему во всех провайдерах
+ MAPI_NO_MAIL = 32768, //Не активировать транспорт
+ MAPI_PASSWORD_UI = 131072, //Отображать только пользовательский интерфейс пароля
+ MAPI_TIMEOUT_SHORT = 1048576, //Минимальное ожидание ресурсов входа в систему
+ MAPI_UNICODE = 0x80000000,
+ MAPI_USE_DEFAULT = 0x00000040
+ }
+
+ ///
+ /// If you're application is running with Elevated Privileges (i.e. as Administrator) and Outlook isn't, the send will fail.
+ /// You will have to tell the user to close all running instances of Outlook and try again.
+ ///
+ [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
+ private static extern MAPI_ERRORS MAPISendMail(
+ IntPtr lhSession,
+ IntPtr hWnd,
+ MapiMessage message,
+ MAPI_FLAGS flg,
+ int rsv);
+
+ #endregion
+
+
+ /// Create and Send mail message.
+ ///
+ /// In fact, the email is not sent immediately, but is cached in the mail client,
+ /// and will be sent when the user launches the mail client.
+ /// If the mail client is already running, the email will be sent at the next synchronization.
+ ///
+ public static bool SendMail(
+ IEnumerable recipients,
+ string strSubject,
+ string strBody,
+ UIFlags UIflags = UIFlags.PopupUI,
+ IWin32Window? parentWindow = null,
+ params string[] attachFiles
+ )
+ {
+ using (MapiMessage msg = new()
+ {
+ subject = strSubject,
+ noteText = strBody
+ })
+ {
+ (msg.hRecips, msg.recipCount) = RecipientsToBuffer(recipients);
+ (msg.hFiles, msg.fileCount) = AttachmentsToBuffer(attachFiles);
+
+ MAPI_FLAGS how = (UIflags == UIFlags.PopupUI) ? (MAPI_FLAGS.MAPI_LOGON_UI | MAPI_FLAGS.MAPI_DIALOG) : (MAPI_FLAGS.MAPI_LOGON_UI);
+ how |= MAPI_FLAGS.MAPI_NEW_SESSION;
+
+ IntPtr hWnd = (parentWindow == null) ? IntPtr.Zero : parentWindow.Handle;
+
+ var Err = MAPISendMail(
+ new IntPtr(0),
+ hWnd,
+ msg,
+ how,
+ 0);
+
+ switch (Err)
+ {
+ case MAPI_ERRORS.OK: return true;
+ case MAPI_ERRORS.UserAbort: return false;
+ case MAPI_ERRORS.NotSupported: return false;//If send with no UI, and user denied send, this occurs.
+ default: throw new MAPIException(Err);
+ }
+ }
+ }
+
+ ///
+ public static bool SendMail(
+ string sendTo,
+ string strSubject,
+ string strBody,
+ UIFlags uiFlags = UIFlags.PopupUI,
+ IWin32Window? parentWindow = null,
+ params string[] attachFiles)
+ => SendMail(
+ new MapiRecipDesc[] { CreateRecipient(sendTo, SendToFlags.MAPI_TO) },
+ strSubject, strBody, uiFlags, parentWindow, attachFiles);
+
+
+ public static MapiRecipDesc CreateRecipient(string email, SendToFlags howTo = SendToFlags.MAPI_TO)
+ => new(email, howTo);
+
+ private static (IntPtr hMem, int Count) RecipientsToBuffer(IEnumerable recipients)
+ {
+ if (!recipients.Any()) throw new ArgumentNullException(nameof(recipients));
+
+ var lRecipients = recipients.ToList();
+
+ int size = Marshal.SizeOf(typeof(MapiRecipDesc));
+ IntPtr hMem = Marshal.AllocHGlobal(lRecipients.Count * size);
+ IntPtr hWrite = hMem;
+ lRecipients.ForEach(mapiDesc =>
+ {
+ Marshal.StructureToPtr(mapiDesc, hWrite, false);
+ hWrite += size;
+ });
+ return (hMem, lRecipients.Count);
+ }
+
+ private static (IntPtr hMem, int fileCount) AttachmentsToBuffer(IEnumerable? attachments = null)
+ {
+ if (attachments == null || !attachments.Any()) return (IntPtr.Zero, 0);
+ if (attachments.Count() > MAX_ATTACHMENTS) throw new ArgumentOutOfRangeException($"{nameof(attachments)}.Count > {MAX_ATTACHMENTS}");
+
+ List lAttachments = attachments.ToList();
+
+ int size = Marshal.SizeOf(typeof(MapiFileDesc));
+ IntPtr hMem = Marshal.AllocHGlobal(lAttachments.Count * size);
+
+ MapiFileDesc mapiFileDesc = new();
+ mapiFileDesc.position = -1;
+
+ IntPtr ptr = hMem;
+ lAttachments.ForEach(path =>
+ {
+ mapiFileDesc.name = Path.GetFileName(path);
+ mapiFileDesc.path = path;
+ Marshal.StructureToPtr(mapiFileDesc, ptr, false);
+ ptr += size;
+ });
+ return (hMem, lAttachments.Count);
+ }
+
+
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ internal class MapiMessage : IDisposable
+ {
+ public int reserved;
+ public string subject;
+ public string noteText;
+ public string messageType;
+ public string dateReceived;
+ public string conversationID;
+ public int flags;
+ public IntPtr hOriginator;
+ public int recipCount;
+ public IntPtr hRecips;
+ public int fileCount;
+ public IntPtr hFiles;
+
+ public void Dispose()
+ {
+ if (hRecips != IntPtr.Zero)
+ {
+ int size = Marshal.SizeOf(typeof(MapiRecipDesc));
+ IntPtr ptr = hRecips;
+ for (int i = 0; i < recipCount; i++)
+ {
+ Marshal.DestroyStructure(ptr, typeof(MapiRecipDesc));
+ ptr += size;
+ }
+ Marshal.FreeHGlobal(hRecips);
+ }
+
+ if (hFiles != IntPtr.Zero)
+ {
+ int size = Marshal.SizeOf(typeof(MapiFileDesc));
+ IntPtr ptr = hFiles;
+ for (int i = 0; i < fileCount; i++)
+ {
+ Marshal.DestroyStructure((IntPtr)ptr,
+ typeof(MapiFileDesc));
+ ptr += size;
+ }
+ Marshal.FreeHGlobal(hFiles);
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ internal class MapiFileDesc
+ {
+ public int reserved;
+ public int flags;
+ public int position;
+ public string path;
+ public string name;
+ public IntPtr hType;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public class MapiRecipDesc
+ {
+ public int reserved = 0;
+ public SendToFlags recipClass = SendToFlags.MAPI_TO;
+
+ /// MAPISendMail hanging with Outlook because the mail addresses had trailing spaces!
+ public string name = String.Empty;
+ public string address = String.Empty;
+ public int eIDSize = 0;
+ public IntPtr hEntryID = IntPtr.Zero;
+
+ private MapiRecipDesc() { }
+
+ public MapiRecipDesc(string email, SendToFlags howTo = SendToFlags.MAPI_TO) : this()
+ {
+ recipClass = howTo;
+ name = email.Trim();
+ }
+ }
+ }
+}
diff --git a/Navferty.Common/WinAPI/WinAPI.Windows.cs b/Navferty.Common/WinAPI/WinAPI.Windows.cs
new file mode 100644
index 0000000..b642c2d
--- /dev/null
+++ b/Navferty.Common/WinAPI/WinAPI.Windows.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+
+#region Structures to interoperate with the Windows API
+
+using word = System.UInt16;
+using dword = System.UInt32;
+using hwnd = System.IntPtr;
+using large_int = System.Int64;
+using ulong_ptr = System.IntPtr;
+
+#endregion
+
+#nullable enable
+
+namespace Navferty.Common.WinAPI
+{
+ internal static class Windows
+ {
+ public enum WindowMessages : int
+ {
+ WM_PAINT = 0xF,
+ EM_SETCUEBANNER = 0x1501
+ }
+
+ [DllImport(Core.WINDLL_USER, SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
+ internal static extern IntPtr SendMessage(
+ [In] hwnd hwnd,
+ [In, MarshalAs(UnmanagedType.I4)] WindowMessages wMsg,
+ [In] int wParam,
+ [In, MarshalAs(UnmanagedType.LPTStr)] string? lParam);
+
+ [DllImport(Core.WINDLL_USER)]
+ private static extern int GetClientRect(
+ [In] hwnd hwnd,
+ [In, Out] ref Rectangle rc);
+
+ public static Rectangle GetClientRect(this IWin32Window wind)
+ {
+ var rcClient = new Rectangle();
+ GetClientRect(wind.Handle, ref rcClient);
+ return rcClient;
+ }
+ }
+
+}
diff --git a/Navferty.Common/WinAPI/WinAPI.cs b/Navferty.Common/WinAPI/WinAPI.cs
deleted file mode 100644
index 8440e6f..0000000
--- a/Navferty.Common/WinAPI/WinAPI.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Drawing;
-using System.Runtime.InteropServices;
-using System.Windows.Forms;
-
-using Microsoft.Win32.SafeHandles;
-
-#nullable enable
-
-namespace Navferty.Common
-{
- internal static class WinAPI
- {
- public enum WindowMessages : int
- {
- WM_PAINT = 0xF,
- EM_SETCUEBANNER = 0x1501
- }
-
- internal const string WINDLL_USER = "user32.dll";
-
- [DllImport(WINDLL_USER, SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
- internal static extern IntPtr SendMessage(
- [In] IntPtr hwnd,
- [In, MarshalAs(UnmanagedType.I4)] WinAPI.WindowMessages wMsg,
- [In] int wParam,
- [In, MarshalAs(UnmanagedType.LPTStr)] string? lParam);
-
- [DllImport(WINDLL_USER)]
- private static extern int GetClientRect(
- [In] IntPtr hwnd,
- [In, Out] ref System.Drawing.Rectangle rc);
-
- public static Rectangle GetClientRect(IWin32Window wind)
- {
- var rcClient = new Rectangle();
- GetClientRect(wind.Handle, ref rcClient);
- return rcClient;
- }
-
-
- internal class DC : SafeHandleZeroOrMinusOneIsInvalid
- {
- [DllImport(WINDLL_USER)]
- private static extern IntPtr GetDC(IntPtr hwnd);
-
- [DllImport(WINDLL_USER)]
- private static extern bool ReleaseDC(IntPtr hwnd, IntPtr hdc);
-
- internal IntPtr hWnd = IntPtr.Zero;
-
- public DC(IntPtr WindowHandle) : base(true)
- {
- var hdc = GetDC(WindowHandle);
- if (hdc == IntPtr.Zero) throw new Win32Exception();
- hWnd = WindowHandle;
- SetHandle(hdc);
- }
-
- public DC(IWin32Window Window) : this(Window.Handle) { }
-
- protected override bool ReleaseHandle()
- {
- if (IsInvalid) return true;
- bool bResult = ReleaseDC(hWnd, handle);
- SetHandle(IntPtr.Zero);
- return bResult;
- }
-
- public Graphics CreateGraphics() => Graphics.FromHdc(DangerousGetHandle());
- }
- }
-}
diff --git a/Navferty.Common/packages.config b/Navferty.Common/packages.config
new file mode 100644
index 0000000..754300b
--- /dev/null
+++ b/Navferty.Common/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Navferty.ExcelAddIn.Web/CurrencyExchangeRates/Manager.cs b/Navferty.ExcelAddIn.Web/CurrencyExchangeRates/Manager.cs
index c390acd..cb4fe05 100644
--- a/Navferty.ExcelAddIn.Web/CurrencyExchangeRates/Manager.cs
+++ b/Navferty.ExcelAddIn.Web/CurrencyExchangeRates/Manager.cs
@@ -9,7 +9,6 @@ namespace Navferty.ExcelAddIn.Web.CurrencyExchangeRates
{
public static class Manager
{
-
public static ExchangeRateRecord? SelectExchageRate(IDialogService dialogService)
{
using (var f = new frmExchangeRates(dialogService))
diff --git a/Navferty.ExcelAddIn.Web/CurrencyExchangeRates/frmExchangeRates.cs b/Navferty.ExcelAddIn.Web/CurrencyExchangeRates/frmExchangeRates.cs
index c354959..6e84cc2 100644
--- a/Navferty.ExcelAddIn.Web/CurrencyExchangeRates/frmExchangeRates.cs
+++ b/Navferty.ExcelAddIn.Web/CurrencyExchangeRates/frmExchangeRates.cs
@@ -254,7 +254,7 @@ private void OnPasteResultToWorkSheet()
var selRows = gridResult.SelectedRowsAsEnumerable();
if (selRows.Count() != 1)
{
- dialogService?.ShowError(UIStrings.CurrencyExchangeRates_Error_CanSelectOnlyOneRow);
+ dialogService?.ShowError(new Exception(UIStrings.CurrencyExchangeRates_Error_CanSelectOnlyOneRow));
return;
}
@@ -265,7 +265,7 @@ private void OnPasteResultToWorkSheet()
}
catch (Exception ex)
{
- dialogService?.ShowError(ex.Message);
+ dialogService?.ShowError(ex);
}
}
diff --git a/Navferty.ExcelAddIn.Web/NLog.config b/Navferty.ExcelAddIn.Web/NLog.config
deleted file mode 100644
index 349d7b8..0000000
--- a/Navferty.ExcelAddIn.Web/NLog.config
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Navferty.ExcelAddIn.Web/Navferty.ExcelAddIn.Web.csproj b/Navferty.ExcelAddIn.Web/Navferty.ExcelAddIn.Web.csproj
index de58509..ed4809c 100644
--- a/Navferty.ExcelAddIn.Web/Navferty.ExcelAddIn.Web.csproj
+++ b/Navferty.ExcelAddIn.Web/Navferty.ExcelAddIn.Web.csproj
@@ -105,9 +105,6 @@
WCF Proxy Generator
Reference.cs
-
- PreserveNewest
-
Designer
@@ -138,6 +135,7 @@
+
diff --git a/NavfertyExcelAddIn.UnitTests/WorksheetCellsEditing/EmptySpaceTrimmerTests.cs b/NavfertyExcelAddIn.UnitTests/WorksheetCellsEditing/EmptySpaceTrimmerTests.cs
index cf94531..3e36b95 100644
--- a/NavfertyExcelAddIn.UnitTests/WorksheetCellsEditing/EmptySpaceTrimmerTests.cs
+++ b/NavfertyExcelAddIn.UnitTests/WorksheetCellsEditing/EmptySpaceTrimmerTests.cs
@@ -11,14 +11,14 @@ namespace NavfertyExcelAddIn.UnitTests.WorksheetCellsEditing
[TestClass]
public class EmptySpaceTrimmerTests : TestsBase
{
- private EmptySpaceTrimmer emptySpaceTrimmer;
+ private TextTrimmer emptySpaceTrimmer;
[TestInitialize]
public void BeforeEachTest()
{
SetRangeExtentionsStub();
- emptySpaceTrimmer = new EmptySpaceTrimmer();
+ emptySpaceTrimmer = new TextTrimmer();
}
[TestMethod]
diff --git a/NavfertyExcelAddIn/Commons/DialogService.cs b/NavfertyExcelAddIn/Commons/DialogService.cs
index 1cd788c..9d127c6 100644
--- a/NavfertyExcelAddIn/Commons/DialogService.cs
+++ b/NavfertyExcelAddIn/Commons/DialogService.cs
@@ -8,8 +8,10 @@
using Navferty.Common;
-using NavfertyExcelAddIn.Localization;
-
+using NavfertyExcelAddIn.Localization;
+
+using NLog;
+
using Application = Microsoft.Office.Interop.Excel.Application;
namespace NavfertyExcelAddIn.Commons
@@ -29,10 +31,14 @@ private static readonly Dictionary ExtensionFilte
{FileType.Pdf, new FileExtensionFilter("PDF files", "*.pdf")}
};
+ [Obsolete("Use ShowError(Exception, ILogger) instead", true)]
public void ShowError(string message)
- {
- MessageBox.Show(message, UIStrings.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ {
+ //MessageBox.Show(message, UIStrings.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ ShowError(new Exception(message));
}
+ public void ShowError(Exception e, ILogger? logger = null)
+ => e.ShowErrorUI(null, logger);
public void ShowInfo(string message)
{
diff --git a/NavfertyExcelAddIn/Commons/ExceptionLogger.cs b/NavfertyExcelAddIn/Commons/ExceptionLogger.cs
index 2d99f2c..c0ccb83 100644
--- a/NavfertyExcelAddIn/Commons/ExceptionLogger.cs
+++ b/NavfertyExcelAddIn/Commons/ExceptionLogger.cs
@@ -30,8 +30,7 @@ public void Intercept(IInvocation invocation)
}
catch (Exception ex)
{
- logger.Error(ex);
- dialogService.ShowError(string.Format(UIStrings.ErrorMessage, ex.Message));
+ dialogService.ShowError(ex, logger);
throw;
}
}
diff --git a/NavfertyExcelAddIn/Feedback/FeedbackBuilder.cs b/NavfertyExcelAddIn/Feedback/FeedbackBuilder.cs
new file mode 100644
index 0000000..6852555
--- /dev/null
+++ b/NavfertyExcelAddIn/Feedback/FeedbackBuilder.cs
@@ -0,0 +1,22 @@
+
+using Navferty.Common;
+
+#nullable enable
+
+namespace NavfertyExcelAddIn.Feedback
+{
+ public class FeedbackBuilder : IFeedback
+ {
+ internal readonly IDialogService dialogService;
+ private Microsoft.Office.Interop.Excel.Application App => Globals.ThisAddIn.Application;
+
+ public FeedbackBuilder(IDialogService dialogService)
+ => this.dialogService = dialogService;
+
+
+ public void DisplayFeedbackUI()
+ {
+ Navferty.Common.Feedback.FeedbackManager.ShowFeedbackUI();
+ }
+ }
+}
diff --git a/NavfertyExcelAddIn/Feedback/IFeedback.cs b/NavfertyExcelAddIn/Feedback/IFeedback.cs
new file mode 100644
index 0000000..72052bc
--- /dev/null
+++ b/NavfertyExcelAddIn/Feedback/IFeedback.cs
@@ -0,0 +1,7 @@
+namespace NavfertyExcelAddIn.Feedback
+{
+ public interface IFeedback
+ {
+ void DisplayFeedbackUI();
+ }
+}
diff --git a/NavfertyExcelAddIn/Localization/RibbonLabels.Designer.cs b/NavfertyExcelAddIn/Localization/RibbonLabels.Designer.cs
index c4502fd..9666620 100644
--- a/NavfertyExcelAddIn/Localization/RibbonLabels.Designer.cs
+++ b/NavfertyExcelAddIn/Localization/RibbonLabels.Designer.cs
@@ -123,6 +123,15 @@ internal static string CutNames {
}
}
+ ///
+ /// Looks up a localized string similar to Feedback.
+ ///
+ internal static string Feedback {
+ get {
+ return ResourceManager.GetString("Feedback", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Find Errors.
///
@@ -303,6 +312,15 @@ internal static string TrimSpaces {
}
}
+ ///
+ /// Looks up a localized string similar to Trim Text.
+ ///
+ internal static string TrimTextByLength {
+ get {
+ return ResourceManager.GetString("TrimTextByLength", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Undo Last Action.
///
diff --git a/NavfertyExcelAddIn/Localization/RibbonLabels.resx b/NavfertyExcelAddIn/Localization/RibbonLabels.resx
index 205170b..c04d8be 100644
--- a/NavfertyExcelAddIn/Localization/RibbonLabels.resx
+++ b/NavfertyExcelAddIn/Localization/RibbonLabels.resx
@@ -237,4 +237,10 @@
Web tools
+
+ Feedback
+
+
+ Trim Text
+
\ No newline at end of file
diff --git a/NavfertyExcelAddIn/Localization/RibbonLabels.ru-RU.resx b/NavfertyExcelAddIn/Localization/RibbonLabels.ru-RU.resx
index 341a4ab..c1d0c22 100644
--- a/NavfertyExcelAddIn/Localization/RibbonLabels.ru-RU.resx
+++ b/NavfertyExcelAddIn/Localization/RibbonLabels.ru-RU.resx
@@ -237,4 +237,10 @@
Защита данных
+
+ Обратная связь
+
+
+ Обрезать текст
+
\ No newline at end of file
diff --git a/NavfertyExcelAddIn/Localization/RibbonSupertips.Designer.cs b/NavfertyExcelAddIn/Localization/RibbonSupertips.Designer.cs
index 50bc47b..319cfb3 100644
--- a/NavfertyExcelAddIn/Localization/RibbonSupertips.Designer.cs
+++ b/NavfertyExcelAddIn/Localization/RibbonSupertips.Designer.cs
@@ -96,6 +96,15 @@ internal static string CutNames {
}
}
+ ///
+ /// Looks up a localized string similar to Send a bug report or feature request to the developer.
+ ///
+ internal static string Feedback {
+ get {
+ return ResourceManager.GetString("Feedback", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Find all cells in the specified range that have any errors (#)..
///
@@ -259,6 +268,15 @@ internal static string TrimSpaces {
}
}
+ ///
+ /// Looks up a localized string similar to Trim cell text by specifed length.
+ ///
+ internal static string TrimTextByLength {
+ get {
+ return ResourceManager.GetString("TrimTextByLength", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Undo the latest action done with this add-in. The undo is possible for certain functions in the sections 'Converting Values' and 'Formatting Values' and only in case the cells' values have not been changed after that action..
///
diff --git a/NavfertyExcelAddIn/Localization/RibbonSupertips.resx b/NavfertyExcelAddIn/Localization/RibbonSupertips.resx
index dfbccb4..0cd31c3 100644
--- a/NavfertyExcelAddIn/Localization/RibbonSupertips.resx
+++ b/NavfertyExcelAddIn/Localization/RibbonSupertips.resx
@@ -196,4 +196,10 @@ Allows rewriting values in range -999 billion to 999 billion, with precision up
Show or hide worksheet tabs
+
+ Send a bug report or feature request to the developer
+
+
+ Trim cell text by specifed length
+
\ No newline at end of file
diff --git a/NavfertyExcelAddIn/Localization/RibbonSupertips.ru-RU.resx b/NavfertyExcelAddIn/Localization/RibbonSupertips.ru-RU.resx
index 2b455cc..bfc9a78 100644
--- a/NavfertyExcelAddIn/Localization/RibbonSupertips.ru-RU.resx
+++ b/NavfertyExcelAddIn/Localization/RibbonSupertips.ru-RU.resx
@@ -196,4 +196,10 @@
Отобразить или скрыть ярлычки листов
+
+ Отправить отчёт об ошибке или пожелание новой функциональности разработчику
+
+
+ Обрезать текст по заданной длинне
+
\ No newline at end of file
diff --git a/NavfertyExcelAddIn/Localization/UIStrings.Designer.cs b/NavfertyExcelAddIn/Localization/UIStrings.Designer.cs
index 11661df..0e597d4 100644
--- a/NavfertyExcelAddIn/Localization/UIStrings.Designer.cs
+++ b/NavfertyExcelAddIn/Localization/UIStrings.Designer.cs
@@ -267,6 +267,42 @@ internal static string SuccessfullyValidatedMessage {
}
}
+ ///
+ /// Looks up a localized string similar to Specify the allowed maximum text length, or 0 for no truncation..
+ ///
+ internal static string TrimTextByLength_TextLen {
+ get {
+ return ResourceManager.GetString("TrimTextByLength_TextLen", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Text clipping.
+ ///
+ internal static string TrimTextByLength_Title {
+ get {
+ return ResourceManager.GetString("TrimTextByLength_Title", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Delete lines consisting of only spaces.
+ ///
+ internal static string TrimTextByLength_TrimFullSpaced {
+ get {
+ return ResourceManager.GetString("TrimTextByLength_TrimFullSpaced", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Trim spaces at the beginning and end of a string.
+ ///
+ internal static string TrimTextByLength_TrimStartEnd {
+ get {
+ return ResourceManager.GetString("TrimTextByLength_TrimStartEnd", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Any unsaved changes will be lost. Active workbook may become corrupted. It is strongly recommended to create backup. Continue?.
///
diff --git a/NavfertyExcelAddIn/Localization/UIStrings.resx b/NavfertyExcelAddIn/Localization/UIStrings.resx
index 9e56c84..b18a8f7 100644
--- a/NavfertyExcelAddIn/Localization/UIStrings.resx
+++ b/NavfertyExcelAddIn/Localization/UIStrings.resx
@@ -186,6 +186,18 @@
Successfully validated, no errors or warnings detected
+
+ Specify the allowed maximum text length, or 0 for no truncation.
+
+
+ Text clipping
+
+
+ Delete lines consisting of only spaces
+
+
+ Trim spaces at the beginning and end of a string
+
Any unsaved changes will be lost. Active workbook may become corrupted. It is strongly recommended to create backup. Continue?
diff --git a/NavfertyExcelAddIn/Localization/UIStrings.ru-RU.resx b/NavfertyExcelAddIn/Localization/UIStrings.ru-RU.resx
index 70c804b..bbac600 100644
--- a/NavfertyExcelAddIn/Localization/UIStrings.ru-RU.resx
+++ b/NavfertyExcelAddIn/Localization/UIStrings.ru-RU.resx
@@ -186,6 +186,18 @@
Валидация успешна, ошибок не обнаружено
+
+ Укажите допустимую максимальную длинну текста, или 0 чтобы не обрезать.
+
+
+ Обрезка текста
+
+
+ Удалять строки состоящие из одних пробелов
+
+
+ Обрезать пробелы в начале и в конце строки
+
Несохранённые изменения будут утеряны. Книга может оказаться повреждённой: настоятельно рекомендуется предварительно создать копию. Продолжить?
diff --git a/NavfertyExcelAddIn/NLog.config b/NavfertyExcelAddIn/NLog.config
index 9bd8602..9c7fd0a 100644
--- a/NavfertyExcelAddIn/NLog.config
+++ b/NavfertyExcelAddIn/NLog.config
@@ -13,6 +13,8 @@
diff --git a/NavfertyExcelAddIn/NavfertyExcelAddIn.csproj b/NavfertyExcelAddIn/NavfertyExcelAddIn.csproj
index be280f2..ae984d3 100644
--- a/NavfertyExcelAddIn/NavfertyExcelAddIn.csproj
+++ b/NavfertyExcelAddIn/NavfertyExcelAddIn.csproj
@@ -240,6 +240,12 @@
+
+ Form
+
+
+ frmTrimParams.cs
+
@@ -266,8 +272,10 @@
-
+
+
+
@@ -291,9 +299,9 @@
-
+
-
+
@@ -393,6 +401,9 @@
InteractiveRangeReportForm.cs
Designer
+
+ frmTrimParams.cs
+
ResXFileCodeGenerator
RibbonSupertips.Designer.cs
diff --git a/NavfertyExcelAddIn/NavfertyRibbon.cs b/NavfertyExcelAddIn/NavfertyRibbon.cs
index eb50693..890640a 100644
--- a/NavfertyExcelAddIn/NavfertyRibbon.cs
+++ b/NavfertyExcelAddIn/NavfertyRibbon.cs
@@ -175,31 +175,31 @@ public void Transliterate(IRibbonControl ribbonControl)
public void UnprotectWorkbook(IRibbonControl ribbonControl)
{
- var wb = App.ActiveWorkbook;
- var path = wb.FullName;
+ try
+ {
+ var wb = App.ActiveWorkbook;
+ var path = wb.FullName;
- logger.Debug($"UnprotectWorkbook {path}");
+ logger.Debug($"UnprotectWorkbook {path}");
- var extension = path.Split('.').LastOrDefault();
+ var extension = path.Split('.').LastOrDefault();
- if (extension != "xlsx" && extension != "xlsm")
- {
- dialogService.ShowError(UIStrings.CannotUnlockPleaseSaveAsXml);
- return;
- }
+ if (extension != "xlsx" && extension != "xlsm")
+ throw new Exception(UIStrings.CannotUnlockPleaseSaveAsXml);
- if (!dialogService.Ask(UIStrings.UnsavedChangesWillBeLostPrompt, UIStrings.Warning))
- {
- return;
- }
-
- wb.Close(false);
+ if (!dialogService.Ask(UIStrings.UnsavedChangesWillBeLostPrompt, UIStrings.Warning))
+ {
+ return;
+ }
+ wb.Close(false);
- var wbUnprotector = GetService();
- wbUnprotector.UnprotectWorkbookWithAllWorksheets(path);
+ var wbUnprotector = GetService();
+ wbUnprotector.UnprotectWorkbookWithAllWorksheets(path);
- App.Workbooks.Open(path);
+ App.Workbooks.Open(path);
+ }
+ catch (Exception ex) { dialogService.ShowError(ex); }
}
public void ProtectUnprotectWorksheets(IRibbonControl ribbonControl)
@@ -262,15 +262,9 @@ public void TrimSpaces(IRibbonControl ribbonControl)
public void TrimExtraSpaces(IRibbonControl ribbonControl)
{
var range = GetSelectionOrUsedRange(App.ActiveSheet);
-
- if (range == null)
- return;
-
+ if (range == null) return;
logger.Debug($"{nameof(TrimExtraSpaces)}. Range selected is {range.Address}");
-
-
- var trimmer = GetService();
- trimmer.TrimExtraSpaces(range);
+ GetService().TrimExtraSpaces(range);
}
public void RemoveAllSpaces(IRibbonControl ribbonControl)
@@ -283,10 +277,19 @@ public void RemoveAllSpaces(IRibbonControl ribbonControl)
logger.Debug($"{nameof(RemoveAllSpaces)}. Range selected is {range.Address}");
- var trimmer = GetService();
+ var trimmer = GetService();
trimmer.RemoveAllSpaces(range);
}
+ public void TrimTextByLength(IRibbonControl ribbonControl)
+ {
+ Range range = GetSelectionOrUsedRange(App.ActiveSheet);
+ if (range == null) return;
+ logger.Debug($"{nameof(TrimTextByLength)}. Range selected is {range.Address}");
+ GetService().TrimTextByLengthUIDisplay(range);
+ }
+
+
public void RepairConditionalFormat(IRibbonControl ribbonControl)
{
var range = GetSelectionOrUsedRange(App.ActiveSheet);
@@ -299,7 +302,6 @@ public void RepairConditionalFormat(IRibbonControl ribbonControl)
formatFixer.FillRange(range);
}
-
public void UnmergeCells(IRibbonControl ribbonControl)
{
var range = GetSelectionOrUsedRange(App.ActiveSheet);
@@ -317,29 +319,30 @@ public void UnmergeCells(IRibbonControl ribbonControl)
public void ValidateValues(IRibbonControl ribbonControl)
{
- var activeSheet = (Worksheet)App.ActiveSheet;
- var range = GetSelectionOrUsedRange(activeSheet);
+ try
+ {
+ var activeSheet = (Worksheet)App.ActiveSheet;
+ var range = GetSelectionOrUsedRange(activeSheet);
- if (range == null)
- return;
+ if (range == null)
+ return;
- logger.Debug($"ValidateValues. Range selected is {range.Address}");
+ logger.Debug($"ValidateValues. Range selected is {range.Address}");
- if (!validationTypeByButtonId.TryGetValue(ribbonControl.Id, out var validationType))
- {
- dialogService.ShowError($"Invalid control id '{ribbonControl.Id}'");
- throw new ArgumentOutOfRangeException($"Invalid control id '{ribbonControl.Id}'");
- }
+ if (!validationTypeByButtonId.TryGetValue(ribbonControl.Id, out var validationType))
+ throw new ArgumentOutOfRangeException($"Invalid control id '{ribbonControl.Id}'");
- logger.Debug($"ValidateValues. Range selected is {range.Address}, validation type {validationType}");
+ logger.Debug($"ValidateValues. Range selected is {range.Address}, validation type {validationType}");
- IReadOnlyCollection results;
+ IReadOnlyCollection results;
- var validator = GetService();
- results = validator.Validate(range, validationType);
+ var validator = GetService();
+ results = validator.Validate(range, validationType);
- form = new InteractiveRangeReportForm(results, activeSheet);
- form.Show();
+ form = new InteractiveRangeReportForm(results, activeSheet);
+ form.Show();
+ }
+ catch (Exception ex) { dialogService.ShowError(ex, logger); }
}
public void FindErrors(IRibbonControl ribbonControl)
@@ -423,6 +426,13 @@ public void CurrencyExchangeRatesSelect(IRibbonControl ribbonControl)
}
#endregion
+ #region Feedback
+ public void FeedbackStart(IRibbonControl ribbonControl)
+ {
+ GetService().DisplayFeedbackUI();
+ }
+ #endregion
+
#endregion
#region Utils
diff --git a/NavfertyExcelAddIn/NavfertyRibbon.xml b/NavfertyExcelAddIn/NavfertyRibbon.xml
index e0f0b67..a0271fa 100644
--- a/NavfertyExcelAddIn/NavfertyRibbon.xml
+++ b/NavfertyExcelAddIn/NavfertyRibbon.xml
@@ -38,6 +38,10 @@
onAction="NumberToWordsFrench" keytip="SF" getScreentip="GetLabel" getSupertip="GetSupertip"/>
+
+
@@ -121,8 +125,15 @@
+
+ size="large" imageMso="InternationalCurrency"
+ keytip="EX" getScreentip="GetLabel" getSupertip="GetSupertip"/>
+
+
+
diff --git a/NavfertyExcelAddIn/Registry.cs b/NavfertyExcelAddIn/Registry.cs
index 2e95668..9474ba9 100644
--- a/NavfertyExcelAddIn/Registry.cs
+++ b/NavfertyExcelAddIn/Registry.cs
@@ -46,8 +46,8 @@ public static IContainer CreateContainer()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(ExceptionLogger));
- builder.RegisterType()
- .As()
+ builder.RegisterType()
+ .As()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(ExceptionLogger));
@@ -133,6 +133,11 @@ public static IContainer CreateContainer()
builder.RegisterType();
+ builder.RegisterType()
+ .As()
+ .EnableInterfaceInterceptors()
+ .InterceptedBy(typeof(ExceptionLogger));
+
builder.RegisterType()
.SingleInstance();
diff --git a/NavfertyExcelAddIn/Web/WebToolsBuilder.cs b/NavfertyExcelAddIn/Web/WebToolsBuilder.cs
index 84f6a7a..cc10712 100644
--- a/NavfertyExcelAddIn/Web/WebToolsBuilder.cs
+++ b/NavfertyExcelAddIn/Web/WebToolsBuilder.cs
@@ -1,4 +1,6 @@
+using System;
+
using Microsoft.Office.Interop.Excel;
using Navferty.Common;
@@ -20,18 +22,20 @@ public WebToolsBuilder(IDialogService dialogService)
public void CurrencyExchangeRates_Show()
{
- Range? sel = App.Selection;
- if (null == sel || sel.Cells == null || sel.Cells.Count < 1)
+ try
{
- dialogService.ShowError(UIStrings.CurrencyExchangeRates_Error_NedAnyCellSelection);
- return;
- }
+ Range? sel = App.Selection;
+ if (null == sel || sel.Cells == null || sel.Cells.Count < 1)
+ throw new Exception(UIStrings.CurrencyExchangeRates_Error_NedAnyCellSelection);
- var rslt = Navferty.ExcelAddIn.Web.CurrencyExchangeRates.Manager.SelectExchageRate(dialogService);
- if (rslt == null) return;//User cancel
- var exchangeRate = rslt.CursFor1Unit;
- sel.Value = exchangeRate;
+ var rslt = Navferty.ExcelAddIn.Web.CurrencyExchangeRates.Manager.SelectExchageRate(dialogService);
+ if (rslt == null) return;//User cancel
+
+ var exchangeRate = rslt.CursFor1Unit;
+ sel.Value = exchangeRate;
+ }
+ catch (Exception ex) { dialogService.ShowError(ex); }
}
}
}
diff --git a/NavfertyExcelAddIn/WorksheetCellsEditing/EmptySpaceTrimmer.cs b/NavfertyExcelAddIn/WorksheetCellsEditing/EmptySpaceTrimmer.cs
deleted file mode 100644
index d005d0b..0000000
--- a/NavfertyExcelAddIn/WorksheetCellsEditing/EmptySpaceTrimmer.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Linq;
-
-using Microsoft.Office.Interop.Excel;
-
-using Navferty.Common;
-
-using NavfertyExcelAddIn.Commons;
-
-using NLog;
-
-namespace NavfertyExcelAddIn.WorksheetCellsEditing
-{
- public class EmptySpaceTrimmer : IEmptySpaceTrimmer
- {
- private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
-
- public void TrimExtraSpaces(Range range)
- {
- logger.Info($"Trim spaces for range {range.GetRelativeAddress()}");
-
- range.ApplyForEachCellOfType(value => value.TrimSpaces());
- }
-
- public void RemoveAllSpaces(Range range)
- {
- logger.Info($"Trim spaces for range {range.GetRelativeAddress()}");
-
- range.ApplyForEachCellOfType(value =>
- {
- if (string.IsNullOrWhiteSpace(value))
- return null;
-
- return new string(value.Where(c => !char.IsWhiteSpace(c)).ToArray());
- });
- }
- }
-}
diff --git a/NavfertyExcelAddIn/WorksheetCellsEditing/IEmptySpaceTrimmer.cs b/NavfertyExcelAddIn/WorksheetCellsEditing/ITextTrimmer.cs
similarity index 69%
rename from NavfertyExcelAddIn/WorksheetCellsEditing/IEmptySpaceTrimmer.cs
rename to NavfertyExcelAddIn/WorksheetCellsEditing/ITextTrimmer.cs
index cbf9e21..15c0f6d 100644
--- a/NavfertyExcelAddIn/WorksheetCellsEditing/IEmptySpaceTrimmer.cs
+++ b/NavfertyExcelAddIn/WorksheetCellsEditing/ITextTrimmer.cs
@@ -2,9 +2,10 @@
namespace NavfertyExcelAddIn.WorksheetCellsEditing
{
- public interface IEmptySpaceTrimmer
+ public interface ITextTrimmer
{
void TrimExtraSpaces(Range range);
void RemoveAllSpaces(Range range);
+ void TrimTextByLengthUIDisplay(Range range);
}
}
diff --git a/NavfertyExcelAddIn/WorksheetCellsEditing/TextTrimmer.cs b/NavfertyExcelAddIn/WorksheetCellsEditing/TextTrimmer.cs
new file mode 100644
index 0000000..063e67c
--- /dev/null
+++ b/NavfertyExcelAddIn/WorksheetCellsEditing/TextTrimmer.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Linq;
+
+using Microsoft.Office.Interop.Excel;
+
+using Navferty.Common;
+
+using NavfertyExcelAddIn.Commons;
+using NavfertyExcelAddIn.Localization;
+
+using NLog;
+
+namespace NavfertyExcelAddIn.WorksheetCellsEditing
+{
+ public class TextTrimmer : ITextTrimmer
+ {
+ private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
+
+ public void TrimExtraSpaces(Range range)
+ {
+ logger.Info($"Trim spaces for range {range.GetRelativeAddress()}");
+
+ range.ApplyForEachCellOfType(value => value.TrimSpaces());
+ }
+
+ public void RemoveAllSpaces(Range range)
+ {
+ logger.Info($"Trim spaces for range {range.GetRelativeAddress()}");
+
+ range.ApplyForEachCellOfType(value =>
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ return null;
+
+ return new string(value.Where(c => !char.IsWhiteSpace(c)).ToArray());
+ });
+ }
+
+ public void TrimTextByLengthUIDisplay(Range range)
+ {
+
+ range.ThrowIfTooManyCellsSelected();
+
+ int maxLen = range
+ .Cells?
+ .Cast()?
+ .Select(cell => (string.IsNullOrEmpty(cell?.Text)
+ ? "" : cell?.Text
+ )?
+ .Length)?.Max() ?? 0;
+
+ using (var f = new TrimTextByLengthUI.frmTrimParams())
+ {
+ f.numMaxLength.Maximum = maxLen;
+ f.numMaxLength.Value = maxLen;
+ f.numMaxLength.Enabled = (maxLen > 0);
+
+
+ f.Text = UIStrings.TrimTextByLength_Title;
+ f.lblTextLength.Text = UIStrings.TrimTextByLength_TextLen;
+ f.chkTrimStartEnd.Text = UIStrings.TrimTextByLength_TrimStartEnd;
+ f.chkTrimFullSpaces.Text = UIStrings.TrimTextByLength_TrimFullSpaced;
+
+ if (f.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
+
+ range
+ .Cells?
+ .Cast()?
+ .ToList()?
+ .ForEach(cell => LimitCellTextLength(
+ cell,
+ (int)f.numMaxLength.Value,
+ f.chkTrimStartEnd.Checked,
+ f.chkTrimFullSpaces.Checked));
+ }
+ }
+
+ /// Trim text to the specifed length
+ /// Text to trim
+ /// length to which trim text
+ /// Trims start and end spaces of the string
+ /// If source is full of spaces, iy will be trimmed to empty
+ private static void LimitCellTextLength(
+ Range? cell,
+ int len,
+ bool trimStartEndSpaces,
+ bool trimFullSpacedStrings)
+ {
+ if (null == cell) return;
+ string? value = cell.Text;
+ if (string.IsNullOrEmpty(value)) return;
+
+ if (trimFullSpacedStrings && string.IsNullOrWhiteSpace(value))
+ {
+ cell.Value = string.Empty;
+ return;
+ };
+
+ value = (value.Length <= len)
+ ? value
+ : value.Substring(0, len);
+
+ if (trimStartEndSpaces) value = value.Trim();
+
+ cell.Value = value;
+ }
+ }
+}
diff --git a/NavfertyExcelAddIn/WorksheetCellsEditing/TrimTextByLengthUI/frmTrimParams.Designer.cs b/NavfertyExcelAddIn/WorksheetCellsEditing/TrimTextByLengthUI/frmTrimParams.Designer.cs
new file mode 100644
index 0000000..8404f8c
--- /dev/null
+++ b/NavfertyExcelAddIn/WorksheetCellsEditing/TrimTextByLengthUI/frmTrimParams.Designer.cs
@@ -0,0 +1,150 @@
+namespace NavfertyExcelAddIn.WorksheetCellsEditing.TrimTextByLengthUI
+{
+ partial class frmTrimParams
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(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()
+ {
+ this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
+ this.btnOk = new System.Windows.Forms.Button();
+ this.lblTextLength = new System.Windows.Forms.Label();
+ this.numMaxLength = new System.Windows.Forms.NumericUpDown();
+ this.chkTrimStartEnd = new System.Windows.Forms.CheckBox();
+ this.chkTrimFullSpaces = new System.Windows.Forms.CheckBox();
+ this.tableLayoutPanel1.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.numMaxLength)).BeginInit();
+ this.SuspendLayout();
+ //
+ // tableLayoutPanel1
+ //
+ this.tableLayoutPanel1.ColumnCount = 2;
+ this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
+ this.tableLayoutPanel1.Controls.Add(this.btnOk, 1, 4);
+ this.tableLayoutPanel1.Controls.Add(this.lblTextLength, 0, 0);
+ this.tableLayoutPanel1.Controls.Add(this.numMaxLength, 1, 0);
+ this.tableLayoutPanel1.Controls.Add(this.chkTrimStartEnd, 0, 1);
+ this.tableLayoutPanel1.Controls.Add(this.chkTrimFullSpaces, 0, 2);
+ this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.tableLayoutPanel1.Location = new System.Drawing.Point(8, 8);
+ this.tableLayoutPanel1.Name = "tableLayoutPanel1";
+ this.tableLayoutPanel1.RowCount = 5;
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F));
+ this.tableLayoutPanel1.Size = new System.Drawing.Size(409, 153);
+ this.tableLayoutPanel1.TabIndex = 0;
+ //
+ // btnOk
+ //
+ this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
+ this.btnOk.Dock = System.Windows.Forms.DockStyle.Right;
+ this.btnOk.Location = new System.Drawing.Point(300, 124);
+ this.btnOk.Name = "btnOk";
+ this.btnOk.Size = new System.Drawing.Size(106, 26);
+ this.btnOk.TabIndex = 0;
+ this.btnOk.Text = "Ok";
+ this.btnOk.UseVisualStyleBackColor = true;
+ //
+ // lblTextLength
+ //
+ this.lblTextLength.AutoSize = true;
+ this.lblTextLength.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.lblTextLength.Location = new System.Drawing.Point(3, 0);
+ this.lblTextLength.Name = "lblTextLength";
+ this.lblTextLength.Size = new System.Drawing.Size(291, 26);
+ this.lblTextLength.TabIndex = 1;
+ this.lblTextLength.Text = "Maximum Text Length:";
+ this.lblTextLength.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // numMaxLength
+ //
+ this.numMaxLength.Dock = System.Windows.Forms.DockStyle.Top;
+ this.numMaxLength.Location = new System.Drawing.Point(300, 3);
+ this.numMaxLength.Name = "numMaxLength";
+ this.numMaxLength.Size = new System.Drawing.Size(106, 20);
+ this.numMaxLength.TabIndex = 2;
+ this.numMaxLength.ThousandsSeparator = true;
+ //
+ // chkTrimStartEnd
+ //
+ this.chkTrimStartEnd.AutoSize = true;
+ this.tableLayoutPanel1.SetColumnSpan(this.chkTrimStartEnd, 2);
+ this.chkTrimStartEnd.Dock = System.Windows.Forms.DockStyle.Top;
+ this.chkTrimStartEnd.Location = new System.Drawing.Point(3, 29);
+ this.chkTrimStartEnd.Name = "chkTrimStartEnd";
+ this.chkTrimStartEnd.Size = new System.Drawing.Size(403, 14);
+ this.chkTrimStartEnd.TabIndex = 3;
+ this.chkTrimStartEnd.Text = "trimStartEndSpaces";
+ this.chkTrimStartEnd.UseVisualStyleBackColor = true;
+ //
+ // chkTrimFullSpaces
+ //
+ this.chkTrimFullSpaces.AutoSize = true;
+ this.tableLayoutPanel1.SetColumnSpan(this.chkTrimFullSpaces, 2);
+ this.chkTrimFullSpaces.Dock = System.Windows.Forms.DockStyle.Top;
+ this.chkTrimFullSpaces.Location = new System.Drawing.Point(3, 49);
+ this.chkTrimFullSpaces.Name = "chkTrimFullSpaces";
+ this.chkTrimFullSpaces.Size = new System.Drawing.Size(403, 14);
+ this.chkTrimFullSpaces.TabIndex = 4;
+ this.chkTrimFullSpaces.Text = "trimFullSpacedStrings";
+ this.chkTrimFullSpaces.UseVisualStyleBackColor = true;
+ //
+ // frmTrimParams
+ //
+ this.AcceptButton = this.btnOk;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(425, 169);
+ this.Controls.Add(this.tableLayoutPanel1);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "frmTrimParams";
+ this.Padding = new System.Windows.Forms.Padding(8);
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "Trim Params";
+ this.tableLayoutPanel1.ResumeLayout(false);
+ this.tableLayoutPanel1.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.numMaxLength)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
+ private System.Windows.Forms.Button btnOk;
+ internal System.Windows.Forms.Label lblTextLength;
+ internal System.Windows.Forms.NumericUpDown numMaxLength;
+ internal System.Windows.Forms.CheckBox chkTrimStartEnd;
+ internal System.Windows.Forms.CheckBox chkTrimFullSpaces;
+ }
+}
diff --git a/NavfertyExcelAddIn/WorksheetCellsEditing/TrimTextByLengthUI/frmTrimParams.cs b/NavfertyExcelAddIn/WorksheetCellsEditing/TrimTextByLengthUI/frmTrimParams.cs
new file mode 100644
index 0000000..d23a228
--- /dev/null
+++ b/NavfertyExcelAddIn/WorksheetCellsEditing/TrimTextByLengthUI/frmTrimParams.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace NavfertyExcelAddIn.WorksheetCellsEditing.TrimTextByLengthUI
+{
+ public partial class frmTrimParams : Navferty.Common.Controls.FormEx
+ {
+ public frmTrimParams()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/NavfertyExcelAddIn/WorksheetCellsEditing/TrimTextByLengthUI/frmTrimParams.resx b/NavfertyExcelAddIn/WorksheetCellsEditing/TrimTextByLengthUI/frmTrimParams.resx
new file mode 100644
index 0000000..29dcb1b
--- /dev/null
+++ b/NavfertyExcelAddIn/WorksheetCellsEditing/TrimTextByLengthUI/frmTrimParams.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/NavfertyExcelAddIn/WorksheetProtectUnprotect/WsProtectorUnprotector.cs b/NavfertyExcelAddIn/WorksheetProtectUnprotect/WsProtectorUnprotector.cs
index 23004af..c410ce9 100644
--- a/NavfertyExcelAddIn/WorksheetProtectUnprotect/WsProtectorUnprotector.cs
+++ b/NavfertyExcelAddIn/WorksheetProtectUnprotect/WsProtectorUnprotector.cs
@@ -1,4 +1,5 @@
-using System.Windows.Forms;
+using System;
+using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
@@ -8,28 +9,27 @@
namespace NavfertyExcelAddIn.WorksheetProtectUnprotect
{
- public class WsProtectorUnprotector : IWsProtectorUnprotector
- {
-
- internal readonly IDialogService dialogService;
- private Microsoft.Office.Interop.Excel.Application App => Globals.ThisAddIn.Application;
-
- public WsProtectorUnprotector(IDialogService dialogService)
- => this.dialogService = dialogService;
-
- public void ProtectUnprotectSelectedWorksheets(Workbook wb)
- {
- Sheets wbSheets = wb.Worksheets;
- if (wbSheets.Count < 1)
- {
- dialogService.ShowError(string.Format(UIStrings.WorkSheetsNotFound, wb.FullName));
- }
-
- using (var f = new frmWorksheetsProtection(this, wb))
- {
- if (f.ShowDialog() != DialogResult.OK) return;
- }
- //MessageBox.Show($"ProtectUnprotectWorksheets {wb.FullName}", wb.FullName);
- }
- }
+ public class WsProtectorUnprotector : IWsProtectorUnprotector
+ {
+
+ internal readonly IDialogService dialogService;
+ private Microsoft.Office.Interop.Excel.Application App => Globals.ThisAddIn.Application;
+
+ public WsProtectorUnprotector(IDialogService dialogService)
+ => this.dialogService = dialogService;
+
+ public void ProtectUnprotectSelectedWorksheets(Workbook wb)
+ {
+ try
+ {
+ Sheets wbSheets = wb.Worksheets;
+ if (wbSheets.Count < 1)
+ throw new Exception(string.Format(UIStrings.WorkSheetsNotFound, wb.FullName));
+
+ using var f = new frmWorksheetsProtection(this, wb);
+ if (f.ShowDialog() != DialogResult.OK) return;
+ }
+ catch (Exception ex) { dialogService.ShowError(ex); }
+ }
+ }
}
diff --git a/NavfertyExcelAddIn/WorksheetProtectUnprotect/frmWorksheetsProtection.cs b/NavfertyExcelAddIn/WorksheetProtectUnprotect/frmWorksheetsProtection.cs
index 63efffc..99cc237 100644
--- a/NavfertyExcelAddIn/WorksheetProtectUnprotect/frmWorksheetsProtection.cs
+++ b/NavfertyExcelAddIn/WorksheetProtectUnprotect/frmWorksheetsProtection.cs
@@ -12,172 +12,169 @@
namespace NavfertyExcelAddIn.WorksheetProtectUnprotect
{
- internal partial class frmWorksheetsProtection : Navferty.Common.Controls.FormEx
- {
-
- private Microsoft.Office.Interop.Excel.Application App => Globals.ThisAddIn.Application;
-
- private readonly WsProtectorUnprotector creator = null;
- private readonly Workbook wb = null;
-
- private Sheets GetSheets() => wb.Worksheets;
-
- public frmWorksheetsProtection()
- {
- InitializeComponent();
- }
-
- public frmWorksheetsProtection(WsProtectorUnprotector Creator, Workbook wb) : this()
- {
- this.creator = Creator;
- this.wb = wb;
-
- Text = $"{RibbonLabels.ProtectUnprotectWorksheets} '{wb.Name}'";
- radioModeProtect.Text = UIStrings.SheetProtection_Set;
- radioModeUnProtect.Text = UIStrings.SheetProtection_Clear;
-
- lblModeDesription.Text = UIStrings.SheetProtection_ProtectionForSheets;
- lblPWD.Text = UIStrings.SheetProtection_Password;
- txtPWD.Text = string.Empty;
-
- btnExecProtectionAction.Text = UIStrings.SheetProtection_Execute;
- btnExecProtectionAction.Enabled = false;
-
- lstWorksheets.EmptyText = UIStrings.NoMatchingWorkSheets;
- lstWorksheets.EmptyTextAlign = ContentAlignment.MiddleCenter;
-
- this.Load += (s, e) => OnFormLoad();
- }
-
- private void OnFormLoad()
- {
- txtPWD.SetVistaCueBanner(UIStrings.SheetProtection_PasswordBanner);
-
- OnSelectProtectAction();
-
- radioModeProtect.CheckedChanged += (s, e) => OnSelectProtectAction();
- lstWorksheets.ItemCheck += OnSheetInListChecked;
- btnExecProtectionAction.Click += (s, e) => OnExecProtectAction();
- }
-
- private bool hasSheetsToProcess = false;
-
- private void OnSelectProtectAction()
- {
- Cursor = Cursors.WaitCursor;
- try
- {
- hasSheetsToProcess = false;
-
- bool bProtect = radioModeProtect.Checked;
- var rows = GetSheets().Cast()
- .Select(ws => new WorksheetRow(ws))
- .Where(wsr => (wsr.HasAnyProtectedObjects() != bProtect))
- .ToArray();
-
- hasSheetsToProcess = rows.Any();
-
- lstWorksheets.Items.Clear();
- if (hasSheetsToProcess)
- {
- lstWorksheets.Items.AddRange(rows);
- int i = 0;
- lstWorksheets.Items.Cast().ToList().ForEach(item =>
- {
- lstWorksheets.SetItemChecked(i, true);
- i++;
- });
- }
- else
- {
- //lstWorksheets.Items.Add(UIStrings.NoMatchingWorkSheets);
- }
-
- }
- catch (Exception ex)
- {
- creator.dialogService.ShowError(ex.Message);
- }
- finally
- {
- lstWorksheets.Enabled = hasSheetsToProcess;//Disable listbox if it have not valid items
- AfterSheetChecked();
- Cursor = Cursors.Default;
- }
- }
-
- private void OnSheetInListChecked(object sender, ItemCheckEventArgs e)
- {
- //inside OnSheetInListChecked() handler, lst.CheckedItems still not return actual row checked staus before methos finished
- //we shcedule our action to execute after exit control events handler pipeline
- ((System.Action)AfterSheetChecked).RunDelayed();
- //And now we exit from event handler, but our delayed AfterSheetChecked() will be run soon...
- }
-
- private void AfterSheetChecked()
- {
- var rowsToProcees = lstWorksheets.CheckedItems.Cast().ToArray();
- hasSheetsToProcess = rowsToProcees.Any();
-
- txtPWD.Enabled = hasSheetsToProcess;
- btnExecProtectionAction.Enabled = hasSheetsToProcess;
- }
-
- private void OnExecProtectAction()
- {
- UseWaitCursor = true;
- try
- {
- var rowsToProcees = lstWorksheets.CheckedItems.Cast().ToArray();
- if (!rowsToProcees.Any())
- {
- creator.dialogService.ShowError(UIStrings.NoMatchingWorkSheets);
- return;
- }
-
- var pwd = txtPWD.Text;
- bool hasPWD = (null != pwd) && (!string.IsNullOrEmpty(pwd));
- bool bProtect = radioModeProtect.Checked;
- bool wasErrorsInProcessingSheets = false;
-
- rowsToProcees.ToList().ForEach(item =>
- {
- try
- {
- Worksheet ws = item.Sheet;
- if (bProtect)
- {
- if (hasPWD)
- ws.Protect(Password: pwd);
- else
- ws.Protect();
- }
- else
- {
- if (hasPWD)
- ws.Unprotect(Password: pwd);
- else
- ws.Unprotect();
- }
- }
- catch (Exception ex)
- {
- wasErrorsInProcessingSheets = true;
- creator.dialogService.ShowError(ex.Message);
- }
- });
- if (!wasErrorsInProcessingSheets) DialogResult = DialogResult.OK;
-
- //was any errors, do not close dialog
- }
- catch (Exception ex)
- {
- creator.dialogService.ShowError(ex.Message);
- }
- finally { UseWaitCursor = false; }
-
- //refill list of sheets with updated protectiob status
- OnSelectProtectAction();
- }
- }
+ internal partial class frmWorksheetsProtection : Navferty.Common.Controls.FormEx
+ {
+
+ private Microsoft.Office.Interop.Excel.Application App => Globals.ThisAddIn.Application;
+
+ private readonly WsProtectorUnprotector creator = null;
+ private readonly Workbook wb = null;
+
+ private Sheets GetSheets() => wb.Worksheets;
+
+ public frmWorksheetsProtection()
+ {
+ InitializeComponent();
+ }
+
+ public frmWorksheetsProtection(WsProtectorUnprotector Creator, Workbook wb) : this()
+ {
+ this.creator = Creator;
+ this.wb = wb;
+
+ Text = $"{RibbonLabels.ProtectUnprotectWorksheets} '{wb.Name}'";
+ radioModeProtect.Text = UIStrings.SheetProtection_Set;
+ radioModeUnProtect.Text = UIStrings.SheetProtection_Clear;
+
+ lblModeDesription.Text = UIStrings.SheetProtection_ProtectionForSheets;
+ lblPWD.Text = UIStrings.SheetProtection_Password;
+ txtPWD.Text = string.Empty;
+
+ btnExecProtectionAction.Text = UIStrings.SheetProtection_Execute;
+ btnExecProtectionAction.Enabled = false;
+
+ lstWorksheets.EmptyText = UIStrings.NoMatchingWorkSheets;
+ lstWorksheets.EmptyTextAlign = ContentAlignment.MiddleCenter;
+
+ this.Load += (s, e) => OnFormLoad();
+ }
+
+ private void OnFormLoad()
+ {
+ txtPWD.SetVistaCueBanner(UIStrings.SheetProtection_PasswordBanner);
+
+ OnSelectProtectAction();
+
+ radioModeProtect.CheckedChanged += (s, e) => OnSelectProtectAction();
+ lstWorksheets.ItemCheck += OnSheetInListChecked;
+ btnExecProtectionAction.Click += (s, e) => OnExecProtectAction();
+ }
+
+ private bool hasSheetsToProcess = false;
+
+ private void OnSelectProtectAction()
+ {
+ Cursor = Cursors.WaitCursor;
+ try
+ {
+ hasSheetsToProcess = false;
+
+ bool bProtect = radioModeProtect.Checked;
+ var rows = GetSheets().Cast()
+ .Select(ws => new WorksheetRow(ws))
+ .Where(wsr => (wsr.HasAnyProtectedObjects() != bProtect))
+ .ToArray();
+
+ hasSheetsToProcess = rows.Any();
+
+ lstWorksheets.Items.Clear();
+ if (hasSheetsToProcess)
+ {
+ lstWorksheets.Items.AddRange(rows);
+ int i = 0;
+ lstWorksheets.Items.Cast().ToList().ForEach(item =>
+ {
+ lstWorksheets.SetItemChecked(i, true);
+ i++;
+ });
+ }
+ else
+ {
+ //lstWorksheets.Items.Add(UIStrings.NoMatchingWorkSheets);
+ }
+
+ }
+ catch (Exception ex)
+ {
+ creator.dialogService.ShowError(ex);
+ }
+ finally
+ {
+ lstWorksheets.Enabled = hasSheetsToProcess;//Disable listbox if it have not valid items
+ AfterSheetChecked();
+ Cursor = Cursors.Default;
+ }
+ }
+
+ private void OnSheetInListChecked(object sender, ItemCheckEventArgs e)
+ {
+ //inside OnSheetInListChecked() handler, lst.CheckedItems still not return actual row checked staus before methos finished
+ //we shcedule our action to execute after exit control events handler pipeline
+ ((System.Action)AfterSheetChecked).RunDelayed();
+ //And now we exit from event handler, but our delayed AfterSheetChecked() will be run soon...
+ }
+
+ private void AfterSheetChecked()
+ {
+ var rowsToProcees = lstWorksheets.CheckedItems.Cast().ToArray();
+ hasSheetsToProcess = rowsToProcees.Any();
+
+ txtPWD.Enabled = hasSheetsToProcess;
+ btnExecProtectionAction.Enabled = hasSheetsToProcess;
+ }
+
+ private void OnExecProtectAction()
+ {
+ UseWaitCursor = true;
+ try
+ {
+ var rowsToProcees = lstWorksheets.CheckedItems.Cast().ToArray();
+ if (!rowsToProcees.Any())
+ throw new Exception(UIStrings.NoMatchingWorkSheets);
+
+ var pwd = txtPWD.Text;
+ bool hasPWD = (null != pwd) && (!string.IsNullOrEmpty(pwd));
+ bool bProtect = radioModeProtect.Checked;
+ bool wasErrorsInProcessingSheets = false;
+
+ rowsToProcees.ToList().ForEach(item =>
+ {
+ try
+ {
+ Worksheet ws = item.Sheet;
+ if (bProtect)
+ {
+ if (hasPWD)
+ ws.Protect(Password: pwd);
+ else
+ ws.Protect();
+ }
+ else
+ {
+ if (hasPWD)
+ ws.Unprotect(Password: pwd);
+ else
+ ws.Unprotect();
+ }
+ }
+ catch (Exception ex)
+ {
+ wasErrorsInProcessingSheets = true;
+ creator.dialogService.ShowError(ex);
+ }
+ });
+ if (!wasErrorsInProcessingSheets) DialogResult = DialogResult.OK;
+
+ //was any errors, do not close dialog
+ }
+ catch (Exception ex)
+ {
+ creator.dialogService.ShowError(ex);
+ }
+ finally { UseWaitCursor = false; }
+
+ //refill list of sheets with updated protectiob status
+ OnSelectProtectAction();
+ }
+ }
}
diff --git a/NavfertyExcelAddIn/app.config b/NavfertyExcelAddIn/app.config
index 7fbc27b..7295457 100644
--- a/NavfertyExcelAddIn/app.config
+++ b/NavfertyExcelAddIn/app.config
@@ -24,9 +24,7 @@
-
+
diff --git a/Set custom feedback email (must replace empty mail inside!).reg b/Set custom feedback email (must replace empty mail inside!).reg
new file mode 100644
index 0000000..e03f46e
Binary files /dev/null and b/Set custom feedback email (must replace empty mail inside!).reg differ