1 /*
2   KeePass Password Safe - The Open-Source Password Manager
3   Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
4 
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19 
20 using System;
21 using System.Collections.Generic;
22 using System.Diagnostics;
23 using System.Text;
24 using System.Threading;
25 using System.Windows.Forms;
26 
27 using KeePass.Forms;
28 
29 using KeePassLib.Interfaces;
30 using KeePassLib.Utility;
31 
32 namespace KeePass.UI
33 {
34 	public sealed class OnDemandStatusDialog : IStatusLogger
35 	{
36 		private readonly bool m_bUseThread;
37 		private readonly Form m_fOwner;
38 
39 		private Thread m_th = null;
40 		private StatusProgressForm m_dlgModal = null;
41 		private readonly object m_objSync = new object();
42 
43 		private const uint InitialProgress = 0;
44 		private const string InitialStatus = null;
45 
46 		private volatile string m_strTitle = null;
47 		private volatile bool m_bTerminate = false;
48 		private volatile uint m_uProgress = InitialProgress;
49 		private volatile string m_strProgress = InitialStatus;
50 
OnDemandStatusDialog(bool bUseThread, Form fOwner)51 		public OnDemandStatusDialog(bool bUseThread, Form fOwner)
52 		{
53 			m_bUseThread = bUseThread;
54 			m_fOwner = fOwner;
55 		}
56 
StartLogging(string strOperation, bool bWriteOperationToLog)57 		public void StartLogging(string strOperation, bool bWriteOperationToLog)
58 		{
59 			m_strTitle = strOperation;
60 		}
61 
EndLogging()62 		public void EndLogging()
63 		{
64 			lock(m_objSync) { m_bTerminate = true; }
65 			m_th = null;
66 
67 			if(m_dlgModal != null)
68 			{
69 				DestroyStatusDialog(m_dlgModal);
70 				m_dlgModal = null;
71 			}
72 		}
73 
SetProgress(uint uPercent)74 		public bool SetProgress(uint uPercent)
75 		{
76 			lock(m_objSync) { m_uProgress = uPercent; }
77 
78 			return ((m_dlgModal != null) ? m_dlgModal.SetProgress(uPercent) : true);
79 		}
80 
SetText(string strNewText, LogStatusType lsType)81 		public bool SetText(string strNewText, LogStatusType lsType)
82 		{
83 			if(strNewText == null) return true;
84 			if(lsType != LogStatusType.Info) return true;
85 
86 			if(m_bUseThread && (m_th == null))
87 			{
88 				ThreadStart ts = new ThreadStart(this.GuiThread);
89 				m_th = new Thread(ts);
90 				m_th.Start();
91 			}
92 			if(!m_bUseThread && (m_dlgModal == null))
93 				m_dlgModal = ConstructStatusDialog();
94 
95 			lock(m_objSync) { m_strProgress = strNewText; }
96 			return ((m_dlgModal != null) ? m_dlgModal.SetText(strNewText, lsType) : true);
97 		}
98 
ContinueWork()99 		public bool ContinueWork()
100 		{
101 			return ((m_dlgModal != null) ? m_dlgModal.ContinueWork() : true);
102 		}
103 
GuiThread()104 		private void GuiThread()
105 		{
106 			uint uProgress = InitialProgress;
107 			string strProgress = InitialStatus;
108 
109 			StatusProgressForm dlg = null;
110 			while(true)
111 			{
112 				lock(m_objSync)
113 				{
114 					if(m_bTerminate) break;
115 
116 					if(m_uProgress != uProgress)
117 					{
118 						uProgress = m_uProgress;
119 						if(dlg != null) dlg.SetProgress(uProgress);
120 					}
121 
122 					if(m_strProgress != strProgress)
123 					{
124 						strProgress = m_strProgress;
125 
126 						if(dlg == null) dlg = ConstructStatusDialog();
127 
128 						dlg.SetText(strProgress, LogStatusType.Info);
129 					}
130 				}
131 
132 				Application.DoEvents();
133 			}
134 
135 			DestroyStatusDialog(dlg);
136 		}
137 
ConstructStatusDialog()138 		private StatusProgressForm ConstructStatusDialog()
139 		{
140 			StatusProgressForm dlg = StatusProgressForm.ConstructEx(
141 				m_strTitle, false, true, (m_bUseThread ? null : m_fOwner), null);
142 			dlg.SetProgress(m_uProgress);
143 
144 			MainForm mfOwner = ((m_fOwner != null) ? (m_fOwner as MainForm) : null);
145 			if((m_bUseThread == false) && (mfOwner != null))
146 			{
147 				// mfOwner.RedirectActivationPush(dlg);
148 				mfOwner.UIBlockInteraction(true);
149 			}
150 
151 			return dlg;
152 		}
153 
DestroyStatusDialog(StatusProgressForm dlg)154 		private void DestroyStatusDialog(StatusProgressForm dlg)
155 		{
156 			if(dlg != null)
157 			{
158 				MainForm mfOwner = ((m_fOwner != null) ? (m_fOwner as MainForm) : null);
159 				if((m_bUseThread == false) && (mfOwner != null))
160 				{
161 					// mfOwner.RedirectActivationPop();
162 					mfOwner.UIBlockInteraction(false);
163 				}
164 
165 				StatusProgressForm.DestroyEx(dlg);
166 
167 				// Conflict with 3116455
168 				// if(mfOwner != null) mfOwner.Activate(); // Prevent disappearing
169 			}
170 		}
171 	}
172 
173 	public sealed class UIBlockerStatusLogger : IStatusLogger
174 	{
175 		private MainForm m_mf;
176 
177 		private string m_strText = string.Empty;
178 		private int m_tLastAnim = Environment.TickCount;
179 		private int m_cDots = 1;
180 
UIBlockerStatusLogger(Form fParent)181 		public UIBlockerStatusLogger(Form fParent)
182 		{
183 			m_mf = (fParent as MainForm);
184 		}
185 
StartLogging(string strOperation, bool bWriteOperationToLog)186 		public void StartLogging(string strOperation, bool bWriteOperationToLog)
187 		{
188 			if(m_mf != null)
189 			{
190 				TaskbarList.SetProgressState(m_mf, TbpFlag.Indeterminate);
191 				m_mf.UIBlockInteraction(true);
192 			}
193 		}
194 
EndLogging()195 		public void EndLogging()
196 		{
197 			if(m_mf != null)
198 			{
199 				m_mf.UIBlockInteraction(false);
200 				TaskbarList.SetProgressState(m_mf, TbpFlag.NoProgress);
201 			}
202 		}
203 
SetProgress(uint uPercent)204 		public bool SetProgress(uint uPercent)
205 		{
206 			Animate();
207 			return true;
208 		}
209 
SetText(string strNewText, LogStatusType lsType)210 		public bool SetText(string strNewText, LogStatusType lsType)
211 		{
212 			if((m_mf != null) && !string.IsNullOrEmpty(strNewText))
213 			{
214 				m_strText = strNewText;
215 				m_mf.SetStatusEx(strNewText);
216 
217 				UIUtil.DoEventsByTime(true);
218 			}
219 			else UIUtil.DoEventsByTime(false);
220 
221 			return true;
222 		}
223 
ContinueWork()224 		public bool ContinueWork()
225 		{
226 			Animate();
227 			return true;
228 		}
229 
Animate()230 		private void Animate()
231 		{
232 			int t = Environment.TickCount, tLast = m_tLastAnim;
233 			int d = t - tLast;
234 
235 			if(d >= 1000)
236 			{
237 				m_tLastAnim = t;
238 
239 				if(m_mf != null)
240 				{
241 					string strDots = new string('.', m_cDots);
242 					m_mf.SetStatusEx(StrUtil.TrimDots(m_strText, false) + strDots);
243 					m_cDots = (m_cDots % 5) + 1; // At least one dot
244 
245 					UIUtil.DoEventsByTime(true);
246 					return;
247 				}
248 			}
249 
250 			UIUtil.DoEventsByTime(false);
251 		}
252 	}
253 }
254