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