source: branches/eraser6/6.0/Eraser/LogForm.cs @ 1659

Revision 1659, 9.0 KB checked in by lowjoel, 4 years ago (diff)

When dealing with the LogForm? and the ProgressForm? classes, for events in which we wait for triggering by the task object, we should check that the form we belong to exists (i.e. not disposed) before we do anything on the form since forms which have Disposed() called will still receive events. There is a fix removed in this revision (in ProgressForm?.cs/WrapItemName) which may introduce new bugs but since this is really hard to reproduce I'll commit a blind fix and wait for more reports to come in.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2009 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.ComponentModel;
25using System.Data;
26using System.Drawing;
27using System.Text;
28using System.Windows.Forms;
29
30using Eraser.Manager;
31using System.Globalization;
32using Eraser.Util;
33using System.IO;
34
35namespace Eraser
36{
37    public partial class LogForm : Form
38    {
39        public LogForm(Task task)
40        {
41            InitializeComponent();
42            UXThemeApi.UpdateControlTheme(this);
43
44            //Update the title
45            Text = string.Format(CultureInfo.InvariantCulture, "{0} - {1}", Text, task.UIText);
46
47            //Populate the list of sessions
48            foreach (DateTime session in task.Log.Entries.Keys)
49                filterSessionCombobox.Items.Add(session);
50            if (task.Log.Entries.Keys.Count != 0)
51                filterSessionCombobox.SelectedIndex = filterSessionCombobox.Items.Count - 1;
52
53            //Set the filter settings
54            filterFilterTypeCombobox.SelectedIndex = 0;
55            filterSeverityCombobox.SelectedIndex = 0;
56
57            //Display the log entries
58            this.task = task;
59            RefreshMessages();
60            EnableButtons();
61
62            //Register our event handler to get live log messages
63            task.Log.Logged += task_Logged;
64            task.Log.NewSession += task_NewSession;
65        }
66
67        private void LogForm_FormClosed(object sender, FormClosedEventArgs e)
68        {
69            task.Log.Logged -= task_Logged;
70        }
71
72        private void filter_Changed(object sender, EventArgs e)
73        {
74            RefreshMessages();
75        }
76
77        private void task_NewSession(object sender, EventArgs e)
78        {
79            if (!IsHandleCreated)
80                return;
81            if (InvokeRequired)
82            {
83                Invoke(new EventHandler<EventArgs>(task_NewSession), sender, e);
84                return;
85            }
86
87            filterSessionCombobox.Items.Add(task.Log.LastSession);
88        }
89
90        private void task_Logged(object sender, LogEventArgs e)
91        {
92            if (!IsHandleCreated)
93                return;
94            if (InvokeRequired)
95            {
96                Invoke(new EventHandler<LogEventArgs>(task_Logged), sender, e);
97                return;
98            }
99
100            //Check whether the current entry meets the criteria for display. Since
101            //this is an event handler for new log messages only, we should only
102            //display this entry when the session in question is the last one.
103            if (filterSessionCombobox.SelectedItem == null ||
104                (DateTime)filterSessionCombobox.SelectedItem != task.Log.LastSession ||
105                !MeetsCriteria(e.LogEntry))
106            {
107                return;
108            }
109
110            //Add it to the cache and increase our virtual list size.
111            entryCache.Add(e.LogEntry);
112            ++log.VirtualListSize;
113
114            //Enable the clear and copy log buttons only if we have entries to copy.
115            EnableButtons();
116        }
117
118        private void log_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
119        {
120            LogEntry entry = entryCache[e.ItemIndex];
121            e.Item = new ListViewItem(entry.Timestamp.ToString("F", CultureInfo.CurrentCulture));
122            e.Item.SubItems.Add(entry.Level.ToString());
123            e.Item.SubItems.Add(entry.Message);
124
125            switch (entry.Level)
126            {
127                case LogLevel.Fatal:
128                    e.Item.ForeColor = Color.Red;
129                    break;
130                case LogLevel.Error:
131                    e.Item.ForeColor = Color.OrangeRed;
132                    break;
133                case LogLevel.Warning:
134                    e.Item.ForeColor = Color.Orange;
135                    break;
136            }
137        }
138
139        private void log_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
140        {
141            if (e.IsSelected)
142            {
143                if (!selectedEntries.ContainsKey(e.ItemIndex))
144                    selectedEntries.Add(e.ItemIndex, null);
145            }
146            else
147            {
148                selectedEntries.Remove(e.ItemIndex);
149            }
150        }
151
152        private void log_VirtualItemsSelectionRangeChanged(object sender, ListViewVirtualItemsSelectionRangeChangedEventArgs e)
153        {
154            for (int i = e.StartIndex; i <= e.EndIndex; ++i)
155            {
156                if (e.IsSelected)
157                {
158                    if (!selectedEntries.ContainsKey(i))
159                        selectedEntries.Add(i, null);
160                }
161                else
162                {
163                    selectedEntries.Remove(i);
164                }
165            }
166        }
167
168        private void logContextMenuStrip_Opening(object sender, CancelEventArgs e)
169        {
170            copySelectedEntriesToolStripMenuItem.Enabled = selectedEntries.Count != 0;
171        }
172
173        private void copySelectedEntriesToolStripMenuItem_Click(object sender, EventArgs e)
174        {
175            //Ensure we've got stuff to copy.
176            if (selectedEntries.Count == 0)
177                return;
178
179            StringBuilder csvText = new StringBuilder();
180            StringBuilder rawText = new StringBuilder();
181            LogSessionDictionary logEntries = task.Log.Entries;
182
183            DateTime sessionTime = (DateTime)filterSessionCombobox.SelectedItem;
184            csvText.AppendLine(S._("Session: {0:F}", sessionTime));
185            rawText.AppendLine(S._("Session: {0:F}", sessionTime));
186
187            int currentEntryIndex = 0;
188            foreach (LogEntry entry in logEntries[sessionTime])
189            {
190                //Only copy entries which meet the display criteria and that they are selected
191                if (!MeetsCriteria(entry))
192                    continue;
193                if (!selectedEntries.ContainsKey(currentEntryIndex++))
194                    continue;
195
196                string timeStamp = entry.Timestamp.ToString("F", CultureInfo.CurrentCulture);
197                string message = entry.Message;
198                csvText.AppendFormat("\"{0}\",\"{1}\",\"{2}\"\n",
199                    timeStamp.Replace("\"", "\"\""), entry.Level.ToString(),
200                    message.Replace("\"", "\"\""));
201                rawText.AppendFormat("{0}   {1} {2}\n", timeStamp, entry.Level.ToString(),
202                    message);
203            }
204
205            if (csvText.Length > 0 || rawText.Length > 0)
206            {
207                //Set the simple text data for data-unaware applications like Word
208                DataObject tableText = new DataObject();
209                tableText.SetText(rawText.ToString());
210
211                //Then a UTF-8 stream CSV for Excel
212                byte[] bytes = Encoding.UTF8.GetBytes(csvText.ToString());
213                MemoryStream tableStream = new MemoryStream(bytes);
214                tableText.SetData(DataFormats.CommaSeparatedValue, tableStream);
215
216                //Set the clipboard
217                Clipboard.SetDataObject(tableText, true);
218            }
219        }
220
221        private void clear_Click(object sender, EventArgs e)
222        {
223            //Clear the backing store
224            task.Log.Clear();
225
226            //Reset the list of sessions
227            filterSessionCombobox.Items.Clear();
228
229            //And reset the list-view control
230            log.VirtualListSize = 0;
231            selectedEntries.Clear();
232            entryCache.Clear();
233
234            //Finally update the UI state.
235            EnableButtons();
236        }
237
238        private void close_Click(object sender, EventArgs e)
239        {
240            Close();
241        }
242
243        /// <summary>
244        /// Checks whether the given log entry meets the current display criteria.
245        /// </summary>
246        /// <param name="entry">The entry to check.</param>
247        /// <returns>True if the entry meets the display criteria.</returns>
248        private bool MeetsCriteria(LogEntry entry)
249        {
250            //Check for the severity
251            switch (filterFilterTypeCombobox.SelectedIndex)
252            {
253                case 0: //and above
254                    if (entry.Level < (LogLevel)filterSeverityCombobox.SelectedIndex)
255                        return false;
256                    break;
257
258                case 1: //equal to
259                    if (entry.Level != (LogLevel)filterSeverityCombobox.SelectedIndex)
260                        return false;
261                    break;
262
263                case 2: //and below
264                    if (entry.Level > (LogLevel)filterSeverityCombobox.SelectedIndex)
265                        return false;
266                    break;
267            }
268
269            return true;
270        }
271
272        /// <summary>
273        /// Updates all messages in the list view to show only those meeting the
274        /// selection criteria.
275        /// </summary>
276        private void RefreshMessages()
277        {
278            //Check if we have a task
279            if (task == null)
280                return;
281
282            Application.UseWaitCursor = true;
283            LogSessionDictionary log = task.Log.Entries;
284            entryCache.Clear();
285            selectedEntries.Clear();
286
287            //Iterate over every key
288            foreach (DateTime sessionTime in log.Keys)
289            {
290                //Check for the session time
291                if (filterSessionCombobox.SelectedItem == null || 
292                    sessionTime != (DateTime)filterSessionCombobox.SelectedItem)
293                    continue;
294
295                foreach (LogEntry entry in log[sessionTime])
296                {
297                    //Check if the entry meets the criteria for viewing
298                    if (MeetsCriteria(entry))
299                        entryCache.Add(entry);
300                }
301            }
302
303            //Set the list view size and update all the control states
304            this.log.VirtualListSize = entryCache.Count;
305            this.log.Refresh();
306            EnableButtons();
307            Application.UseWaitCursor = false;
308        }
309
310        /// <summary>
311        /// Enables/disables buttons based on the current system state.
312        /// </summary>
313        private void EnableButtons()
314        {
315            clear.Enabled = task.Log.Entries.Count > 0;
316        }
317
318        /// <summary>
319        /// The task which this log is displaying entries for
320        /// </summary>
321        private Task task;
322
323        /// <summary>
324        /// Stores all log entries fulfilling the current criteria for rapid access.
325        /// </summary>
326        private List<LogEntry> entryCache = new List<LogEntry>();
327
328        /// <summary>
329        /// Stores all currently selected list view entry indices.
330        /// </summary>
331        private SortedList<int, object> selectedEntries = new SortedList<int, object>();
332    }
333}
Note: See TracBrowser for help on using the repository browser.