Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

407 lines
11 KiB

  1. //=============================================================================
  2. // The CUndoLog is used to implement a log of undo entries to allow MSConfig
  3. // to reverse any changes it may have made. Each tab object is responsible for
  4. // writing a string when it makes changes - this string can be used to undo
  5. // the changes the tab made.
  6. //
  7. // The undo log file will look like this:
  8. //
  9. // ["timestamp" tabname "description" <SHOW|FINAL>]
  10. // tab specific string - any line starting with a "[" will have a
  11. // backslash preceding it
  12. //
  13. // The entries will be arranged in chronological order (most recent first).
  14. // The "description" field will be the only one shown to the user - so it
  15. // will be the only one which needs to be localized. The tab is responsible
  16. // for supplying this text.
  17. //=============================================================================
  18. #pragma once
  19. #include "pagebase.h"
  20. //-----------------------------------------------------------------------------
  21. // This class encapsulates an undo entry (instance of this class will be
  22. // saved in a list).
  23. //-----------------------------------------------------------------------------
  24. class CUndoLogEntry
  25. {
  26. public:
  27. enum UndoEntryState { SHOW, FINAL, UNDONE };
  28. CUndoLogEntry() : m_state(SHOW) {};
  29. CUndoLogEntry(const CString & strTab, const CString & strDescription, const CString & strEntry, const COleDateTime & timestamp)
  30. : m_strTab(strTab),
  31. m_strDescription(strDescription),
  32. m_strEntry(strEntry),
  33. m_timestamp(timestamp),
  34. m_state(SHOW)
  35. {};
  36. CUndoLogEntry(const CString & strTab, const CString & strDescription, const CString & strEntry)
  37. : m_strTab(strTab),
  38. m_strDescription(strDescription),
  39. m_strEntry(strEntry),
  40. m_timestamp(COleDateTime::GetCurrentTime()),
  41. m_state(SHOW)
  42. {};
  43. private:
  44. CUndoLogEntry(const CString & strTab, const CString & strDescription, const CString & strEntry, const COleDateTime & timestamp, UndoEntryState state)
  45. : m_strTab(strTab),
  46. m_strDescription(strDescription),
  47. m_strEntry(strEntry),
  48. m_timestamp(timestamp),
  49. m_state(state)
  50. {};
  51. public:
  52. static CUndoLogEntry * ReadFromFile(CStdioFile & infile)
  53. {
  54. CString strTab, strDescription, strEntry;
  55. UndoEntryState state;
  56. COleDateTime timestamp;
  57. CString strLine;
  58. if (!infile.ReadString(strLine))
  59. return NULL;
  60. strLine.TrimLeft(_T("[\""));
  61. CString strTimestamp = strLine.SpanExcluding(_T("\""));
  62. strLine = strLine.Mid(strTimestamp.GetLength());
  63. timestamp.ParseDateTime(strTimestamp);
  64. strLine.TrimLeft(_T(" \""));
  65. strTab = strLine.SpanExcluding(_T(" "));
  66. strLine = strLine.Mid(strTab.GetLength());
  67. strLine.TrimLeft(_T(" \""));
  68. strDescription = strLine.SpanExcluding(_T("\""));
  69. strLine = strLine.Mid(strDescription.GetLength());
  70. strLine.TrimLeft(_T(" \""));
  71. CString strFinal = strLine.SpanExcluding(_T("]"));
  72. if (strFinal.CompareNoCase(_T("final")) == 0)
  73. state = FINAL;
  74. else if (strFinal.CompareNoCase(_T("show")) == 0)
  75. state = SHOW;
  76. else
  77. state = UNDONE;
  78. strLine.Empty();
  79. for (;;)
  80. {
  81. if (!infile.ReadString(strLine))
  82. break;
  83. if (strLine.IsEmpty())
  84. continue;
  85. if (strLine[0] == _T('['))
  86. {
  87. // We read the first line of the next entry. Back up in the file (including the
  88. // newline and CR characters).
  89. infile.Seek(-1 * (strLine.GetLength() + 2) * sizeof(TCHAR), CFile::current);
  90. break;
  91. }
  92. if (strLine[0] == _T('\\'))
  93. strLine = strLine.Mid(1);
  94. strEntry += strLine + _T("\n");
  95. }
  96. return new CUndoLogEntry(strTab, strDescription, strEntry, timestamp, state);
  97. }
  98. BOOL WriteToFile(CStdioFile & outfile)
  99. {
  100. ASSERT(!m_strTab.IsEmpty());
  101. CString strLine;
  102. strLine = _T("[\"") + m_timestamp.Format() + _T("\" ");
  103. strLine += m_strTab + _T(" \"");
  104. strLine += m_strDescription + _T("\" ");
  105. switch (m_state)
  106. {
  107. case FINAL:
  108. strLine += _T("FINAL");
  109. break;
  110. case UNDONE:
  111. strLine += _T("UNDONE");
  112. break;
  113. case SHOW:
  114. default:
  115. strLine += _T("SHOW");
  116. break;
  117. }
  118. strLine += _T("]\n");
  119. outfile.WriteString(strLine); // TBD - catch the exception
  120. CString strWorking(m_strEntry);
  121. while (!strWorking.IsEmpty())
  122. {
  123. strLine = strWorking.SpanExcluding(_T("\n\r"));
  124. strWorking = strWorking.Mid(strLine.GetLength());
  125. strWorking.TrimLeft(_T("\n\r"));
  126. if (!strLine.IsEmpty() && strLine[0] == _T('['))
  127. strLine = _T("\\") + strLine;
  128. strLine += _T("\n");
  129. outfile.WriteString(strLine);
  130. }
  131. return TRUE;
  132. }
  133. ~CUndoLogEntry() {};
  134. CString m_strTab;
  135. CString m_strDescription;
  136. CString m_strEntry;
  137. COleDateTime m_timestamp;
  138. UndoEntryState m_state;
  139. };
  140. //-----------------------------------------------------------------------------
  141. // This class implements the undo log.
  142. //-----------------------------------------------------------------------------
  143. class CUndoLog
  144. {
  145. public:
  146. CUndoLog() : m_fChanges(FALSE), m_pmapTabs(NULL)
  147. {
  148. }
  149. ~CUndoLog()
  150. {
  151. while (!m_entrylist.IsEmpty())
  152. {
  153. CUndoLogEntry * pEntry = (CUndoLogEntry *)m_entrylist.RemoveHead();
  154. if (pEntry)
  155. delete pEntry;
  156. }
  157. };
  158. //-------------------------------------------------------------------------
  159. // These functions will load the undo log from a file, or save to a file.
  160. // Note - saving to a file will overwrite the contents of the file with
  161. // the contents of the undo log.
  162. //-------------------------------------------------------------------------
  163. BOOL LoadFromFile(LPCTSTR szFilename)
  164. {
  165. ASSERT(szFilename);
  166. if (szFilename == NULL)
  167. return FALSE;
  168. CStdioFile logfile;
  169. if (logfile.Open(szFilename, CFile::modeRead | CFile::typeText))
  170. {
  171. CUndoLogEntry * pEntry;
  172. while (pEntry = CUndoLogEntry::ReadFromFile(logfile))
  173. m_entrylist.AddTail((void *) pEntry);
  174. logfile.Close();
  175. return TRUE;
  176. }
  177. return FALSE;
  178. }
  179. BOOL SaveToFile(LPCTSTR szFilename)
  180. {
  181. ASSERT(szFilename);
  182. if (szFilename == NULL)
  183. return FALSE;
  184. if (!m_fChanges)
  185. return TRUE;
  186. CStdioFile logfile;
  187. if (logfile.Open(szFilename, CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive | CFile::typeText))
  188. {
  189. for (POSITION pos = m_entrylist.GetHeadPosition(); pos != NULL;)
  190. {
  191. CUndoLogEntry * pEntry = (CUndoLogEntry *)m_entrylist.GetNext(pos);
  192. if (pEntry != NULL)
  193. pEntry->WriteToFile(logfile);
  194. }
  195. logfile.Close();
  196. return TRUE;
  197. }
  198. return FALSE;
  199. }
  200. //-------------------------------------------------------------------------
  201. // How many undo entries are in this log?
  202. //-------------------------------------------------------------------------
  203. int GetUndoEntryCount()
  204. {
  205. int iCount = 0;
  206. for (POSITION pos = m_entrylist.GetHeadPosition(); pos != NULL;)
  207. {
  208. CUndoLogEntry * pEntry = (CUndoLogEntry *)m_entrylist.GetNext(pos);
  209. if (pEntry != NULL && pEntry->m_state == CUndoLogEntry::SHOW)
  210. iCount += 1;
  211. }
  212. return iCount;
  213. }
  214. //-------------------------------------------------------------------------
  215. // Get information about a specific entry (returns FALSE for bad index).
  216. //-------------------------------------------------------------------------
  217. BOOL GetUndoEntryInfo(int iIndex, CString & strDescription, COleDateTime & timestamp)
  218. {
  219. CUndoLogEntry * pEntry = GetEntryByIndex(iIndex);
  220. if (pEntry != NULL)
  221. {
  222. strDescription = pEntry->m_strDescription;
  223. timestamp = pEntry->m_timestamp;
  224. return TRUE;
  225. }
  226. return FALSE;
  227. }
  228. //-------------------------------------------------------------------------
  229. // Get the entry data (to pass to a tab to undo). FALSE for bad index.
  230. //-------------------------------------------------------------------------
  231. BOOL GetUndoEntry(int iIndex, CString * pstrTab, CString * pstrEntry)
  232. {
  233. CUndoLogEntry * pEntry = GetEntryByIndex(iIndex);
  234. if (pEntry != NULL)
  235. {
  236. if (pstrTab) *pstrTab = pEntry->m_strTab;
  237. if (pstrEntry) *pstrEntry = pEntry->m_strEntry;
  238. return TRUE;
  239. }
  240. return FALSE;
  241. }
  242. //-------------------------------------------------------------------------
  243. // Mark an entry as final (stays in the file, but marked so it won't
  244. // appear in the undo log). FALSE for bad index.
  245. //-------------------------------------------------------------------------
  246. BOOL MarkUndoEntryFinal(int iIndex)
  247. {
  248. CUndoLogEntry * pEntry = GetEntryByIndex(iIndex);
  249. if (pEntry != NULL)
  250. {
  251. pEntry->m_state = CUndoLogEntry::FINAL;
  252. m_fChanges = TRUE;
  253. return TRUE;
  254. }
  255. return FALSE;
  256. }
  257. //-------------------------------------------------------------------------
  258. // Delete all entries in the log that are older than
  259. // timestampOlderThanThis. The entries will be gone, purged from the file.
  260. //-------------------------------------------------------------------------
  261. BOOL DeleteOldUndoEntries(const COleDateTime & timestampOlderThanThis)
  262. {
  263. m_fChanges = TRUE;
  264. return FALSE;
  265. }
  266. //-------------------------------------------------------------------------
  267. // Create a new undo entry, using the current time, and add it to the
  268. // end of the undo log. Shouldn't return FALSE unless there is no memory.
  269. //-------------------------------------------------------------------------
  270. BOOL AddUndoEntry(const CString & strTab, const CString & strDescription, const CString & strEntry)
  271. {
  272. CUndoLogEntry * pEntry = new CUndoLogEntry(strTab, strDescription, strEntry);
  273. if (pEntry == NULL)
  274. return FALSE;
  275. m_entrylist.AddHead((void *)pEntry);
  276. m_fChanges = TRUE;
  277. return TRUE;
  278. }
  279. //-------------------------------------------------------------------------
  280. // Called to undo the effects of one of the entries. This function will
  281. // need to find the appropriate tab and call its undo function.
  282. //-------------------------------------------------------------------------
  283. BOOL UndoEntry(int iIndex)
  284. {
  285. CUndoLogEntry * pEntry = GetEntryByIndex(iIndex);
  286. if (!pEntry)
  287. return FALSE;
  288. if (pEntry->m_state != CUndoLogEntry::SHOW)
  289. return FALSE;
  290. if (!m_pmapTabs)
  291. return FALSE;
  292. CPageBase * pPage;
  293. if (!m_pmapTabs->Lookup(pEntry->m_strTab, (void * &)pPage) || !pPage)
  294. return FALSE;
  295. // if (!pPage->Undo(pEntry->m_strEntry))
  296. // return FALSE;
  297. pEntry->m_state = CUndoLogEntry::UNDONE;
  298. m_fChanges = TRUE;
  299. return TRUE;
  300. }
  301. //-------------------------------------------------------------------------
  302. // Sets a pointer to the map from tab name to pointer.
  303. //-------------------------------------------------------------------------
  304. void SetTabMap(CMapStringToPtr * pmap)
  305. {
  306. m_pmapTabs = pmap;
  307. }
  308. private:
  309. CUndoLogEntry * GetEntryByIndex(int iIndex)
  310. {
  311. CUndoLogEntry * pEntry = NULL;
  312. POSITION pos = m_entrylist.GetHeadPosition();
  313. do
  314. {
  315. if (pos == NULL)
  316. return NULL;
  317. pEntry = (CUndoLogEntry *)m_entrylist.GetNext(pos);
  318. if (pEntry != NULL && pEntry->m_state == CUndoLogEntry::SHOW)
  319. iIndex -= 1;
  320. } while (iIndex >= 0);
  321. return pEntry;
  322. }
  323. private:
  324. //-------------------------------------------------------------------------
  325. // Member variables.
  326. //-------------------------------------------------------------------------
  327. CMapStringToPtr * m_pmapTabs; // map from tab name to CPageBase pointers
  328. CPtrList m_entrylist; // list of CUndoLogEntry pointers
  329. BOOL m_fChanges; // was the log changed?
  330. };