OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #region | |
6 | |
7 using System; | |
8 using System.Collections.Generic; | |
9 using System.ComponentModel; | |
10 using System.Windows.Forms; | |
11 using Google.NaClVsx.DebugSupport.DWARF; | |
12 using NaClVsx; | |
13 | |
14 #endregion | |
15 | |
16 namespace SymbolDBViewer { | |
17 /// <summary> | |
18 /// So far, this is the only real class in this app. It contains a few | |
19 /// controls and a TreeView of the contents of SymbolDatabase. | |
20 /// The display components are: | |
21 /// - A status display which is used to indicate load progress to the | |
22 /// user (Bottom). | |
23 /// - A fileName label which shows the name of the nexe file that is | |
24 /// currently loaded (Top Left). | |
25 /// The controls are: | |
26 /// - A "Load Nexe" button to pick a file to examine. | |
27 /// - A textfield and "Search" button to search through the Symbol Data. | |
28 /// - A "Close All" button to close any expanded nodes. | |
29 /// - A set of navigation controls to make iterating through search | |
30 /// results easier, consiting of a back button, forward button, and a | |
31 /// label to indicate the currently selected entry and the total number | |
32 /// of hits. | |
33 /// </summary> | |
34 public partial class NexeLoader : Form { | |
35 /// <summary> | |
36 /// The constructor initializes the data fields for the loadStatus | |
37 /// indicator. | |
38 /// </summary> | |
39 public NexeLoader() { | |
40 InitializeComponent(); | |
41 dieLoader_.DictionaryName = "DIEs"; | |
42 fileLoader_.DictionaryName = "Files"; | |
43 locationLoader_.DictionaryName = "Locations"; | |
44 scopeTransitionLoader_.DictionaryName = "Scope Transitions"; | |
45 locListLoader_.DictionaryName = "LocLists"; | |
46 callFrameLoader_.DictionaryName = "Call Frames"; | |
47 } | |
48 | |
49 #region Private Implementation | |
50 | |
51 /// <summary> | |
52 /// A Container used to store nodes that match the user's search. | |
53 /// </summary> | |
54 private List<TreeNode> matchingNodes_; | |
55 | |
56 /// <summary> | |
57 /// The index that the searchNav control cluster is currently on. | |
58 /// </summary> | |
59 private int searchIndex_ = -1; | |
60 | |
61 #endregion | |
62 | |
63 #region Private Implementation | |
64 | |
65 /// <summary> | |
66 /// Searches through the tree and expands and collects any nodes that | |
67 /// match the search string. The parents of any nodes that match are | |
68 /// also expanded to ensure that the search results are all visible. | |
69 /// </summary> | |
70 /// <param name = "nodes">The set of starting nodes to examine.</param> | |
71 /// <param name = "searchString">The string to match against.</param> | |
72 /// <returns>A collection of nodes that have already been expanded and | |
73 /// that match the search results. In cases where parents and children | |
74 /// both match, only the matching children are returned.</returns> | |
75 private static List<TreeNode> FindAndExpandMatchingNodes( | |
76 TreeNodeCollection nodes, string searchString) { | |
77 var matchingNodes = new List<TreeNode>(); | |
78 for (var i = 0; i < nodes.Count; i++) { | |
79 var node = nodes[i]; | |
80 // Doesn't add itself if it already has a matching child. | |
81 var matchingChildren = FindAndExpandMatchingNodes( | |
82 node.Nodes, searchString); | |
83 if (matchingChildren.Count > 0) { | |
84 matchingNodes.AddRange(matchingChildren); | |
85 node.Expand(); | |
86 } else if (node.Text.Contains(searchString)) { | |
87 matchingNodes.Add(node); | |
88 node.Expand(); | |
89 } | |
90 } | |
91 return matchingNodes; | |
92 } | |
93 | |
94 /// <summary> | |
95 /// An event handler that can be called when the users wants to close | |
96 /// any open nodes in the TreeView. | |
97 /// </summary> | |
98 /// <param name = "sender">Unused.</param> | |
99 /// <param name = "e">Unused.</param> | |
100 private void CloseAllButtonClick(object sender, EventArgs e) { | |
101 symbolDbTreeView_.CollapseAll(); | |
102 } | |
103 | |
104 /// <summary> | |
105 /// An event handler that can be called when the user wants to load a | |
106 /// new nexe into the SymbolDBViewer. | |
107 /// </summary> | |
108 /// <param name = "sender">Unused.</param> | |
109 /// <param name = "e">Unused.</param> | |
110 private void HandleLoadButtonClick(object sender, EventArgs e) { | |
111 searchNavLabel_.Text = @"0/0"; | |
112 nexeChooserDialog_.InitialDirectory = | |
113 Environment.GetEnvironmentVariable("NACL_VSX_ROOT"); | |
114 // Show the dialog and get result. | |
115 var result = nexeChooserDialog_.ShowDialog(); | |
116 if (result == DialogResult.OK) { | |
117 statusLabel_.Text = string.Format( | |
118 "Loading :" + nexeChooserDialog_.SafeFileName); | |
119 LoadNexeFile(); | |
120 symbolDbTreeView_.BeginUpdate(); | |
121 symbolDbTreeView_.Nodes.Clear(); | |
122 symbolDbTreeView_.EndUpdate(); | |
123 | |
124 dieLoader_.Content = symbolDatabase_.Entries; | |
125 fileLoader_.Content = symbolDatabase_.Files; | |
126 locationLoader_.Content = symbolDatabase_.Locations; | |
127 scopeTransitionLoader_.Content = symbolDatabase_.ScopeTransitions; | |
128 callFrameLoader_.Content = symbolDatabase_.CallFrames; | |
129 locListLoader_.Content = symbolDatabase_.LocLists; | |
130 | |
131 dieLoader_.RunWorkerAsync(); | |
132 fileLoader_.RunWorkerAsync(); | |
133 locationLoader_.RunWorkerAsync(); | |
134 scopeTransitionLoader_.RunWorkerAsync(); | |
135 callFrameLoader_.RunWorkerAsync(); | |
136 locListLoader_.RunWorkerAsync(); | |
137 } | |
138 Console.WriteLine(result); // <-- For debugging use only. | |
139 } | |
140 | |
141 /// <summary> | |
142 /// Checks all statuses to see if the nexe has finished loading. | |
143 /// </summary> | |
144 /// <returns>True if the TreeView is complete. False, otherwise. | |
145 /// </returns> | |
146 private bool IsLoadingComplete() { | |
147 return (dieLoader_.DoneLoading() && | |
148 fileLoader_.DoneLoading() && | |
149 locationLoader_.DoneLoading() && | |
150 scopeTransitionLoader_.DoneLoading() && | |
151 callFrameLoader_.DoneLoading() && | |
152 locListLoader_.DoneLoading()); | |
153 } | |
154 | |
155 | |
156 /// <summary> | |
157 /// Initializes a new SymbolDatabase with a given nexe. | |
158 /// </summary> | |
159 /// <param name = "filePath">Location of the nexe to use.</param> | |
160 /// <returns>true unless the nexe failed to load for some reason. | |
161 /// </returns> | |
162 bool LoadNexe(string filePath) { | |
163 try { | |
164 symbolDatabase_ = new SymbolDatabase(); | |
165 DwarfParser.DwarfParseElf( | |
166 filePath, new DwarfReaderImpl(symbolDatabase_)); | |
167 symbolDatabase_.BuildIndices(); | |
168 return true; | |
169 } | |
170 catch (Exception) { | |
171 return false; | |
172 } | |
173 } | |
174 | |
175 /// <summary> | |
176 /// Loads the file most recently selected by the user in the | |
177 /// FileChooser. | |
178 /// </summary> | |
179 void LoadNexeFile() { | |
180 var filePath = nexeChooserDialog_.FileName; | |
181 var fileName = nexeChooserDialog_.SafeFileName; | |
182 if (LoadNexe(filePath)) { | |
183 fileNameLabel_.Text = fileName + @": "; | |
184 Refresh(); | |
185 } | |
186 } | |
187 | |
188 /// <summary> | |
189 /// Updates that status area on the bottom of the screen with the | |
190 /// current progress in loading the SymbolData into the TreeView. | |
191 /// </summary> | |
192 /// <param name = "sender">The BackgroundWorker that is reporting progress. | |
193 /// </param> | |
194 /// <param name = "e">The progress report.</param> | |
195 private void PopulateNodesProgressChanged(object sender, | |
196 ProgressChangedEventArgs e) { | |
197 ReprintLoadProgress(); | |
198 } | |
199 | |
200 /// <summary> | |
201 /// Prints the current load status for each of the tables that is] | |
202 /// represented in our TreeView. | |
203 /// </summary> | |
204 private void ReprintLoadProgress() { | |
205 statusLabel_.Text = string.Format( | |
206 "Loading Progress: DIEs: {0}% Files: {1}% Locations: {2}% Scope Transi
tions: {3}% Call Frames: {4}% Loc Lists: {5}%", | |
207 dieLoader_.LoadPercentage, | |
208 fileLoader_.LoadPercentage, | |
209 locationLoader_.LoadPercentage, | |
210 scopeTransitionLoader_.LoadPercentage, | |
211 callFrameLoader_.LoadPercentage, | |
212 locListLoader_.LoadPercentage); | |
213 } | |
214 | |
215 /// <summary> | |
216 /// Runs a search on the symbolDbTreeView_ for any text the user has | |
217 /// entered in the search text box. | |
218 /// </summary> | |
219 /// <param name = "sender">Unused.</param> | |
220 /// <param name = "e">Unused.</param> | |
221 private void SearchButtonClick(object sender, EventArgs e) { | |
222 var searchString = searchTextBox_.Text; | |
223 symbolDbTreeView_.BeginUpdate(); | |
224 matchingNodes_ = FindAndExpandMatchingNodes( | |
225 symbolDbTreeView_.Nodes, searchString); | |
226 symbolDbTreeView_.EndUpdate(); | |
227 if (matchingNodes_.Count > 0) { | |
228 searchIndex_ = 0; | |
229 UpdateSearchNavLabel(); | |
230 } else { | |
231 searchNavLabel_.Text = @"0/0"; | |
232 } | |
233 } | |
234 | |
235 /// <summary> | |
236 /// Navigates one step forward in the search results. | |
237 /// </summary> | |
238 /// <param name = "sender">Unused.</param> | |
239 /// <param name = "e">Unused.</param> | |
240 private void SearchNavBackButtonClick(object sender, EventArgs e) { | |
241 if (searchIndex_ > 0) { | |
242 --searchIndex_; | |
243 UpdateSearchNavLabel(); | |
244 } | |
245 } | |
246 | |
247 /// <summary> | |
248 /// Navigates one step backward in the search results. | |
249 /// </summary> | |
250 /// <param name = "sender">Unused.</param> | |
251 /// <param name = "e">Unused.</param> | |
252 private void SearchNavForwardButtonClick(object sender, EventArgs e) { | |
253 if (searchIndex_ + 1 < matchingNodes_.Count) { | |
254 ++searchIndex_; | |
255 UpdateSearchNavLabel(); | |
256 } | |
257 } | |
258 | |
259 /// <summary> | |
260 /// Updates the Display to indicate which search result is currently | |
261 /// selected. | |
262 /// </summary> | |
263 private void UpdateSearchNavLabel() { | |
264 symbolDbTreeView_.SelectedNode = matchingNodes_[searchIndex_]; | |
265 searchNavLabel_.Text = string.Format( | |
266 "{0}/{1}", searchIndex_ + 1, matchingNodes_.Count); | |
267 } | |
268 | |
269 /// <summary> | |
270 /// Updates the TreeView when a DictionaryLoader worker finishes | |
271 /// creating the subtree it is responsible for. | |
272 /// </summary> | |
273 /// <param name = "sender">The DictionaryLoader that has just finished. | |
274 /// </param> | |
275 /// <param name = "e">The output of the DictionaryLoader, which contains | |
276 /// the finished subtree.</param> | |
277 private void UpdateTreeView(object sender, | |
278 RunWorkerCompletedEventArgs e) { | |
279 ReprintLoadProgress(); | |
280 var node = e.Result as TreeNode; | |
281 if (node != null) { | |
282 symbolDbTreeView_.BeginUpdate(); | |
283 symbolDbTreeView_.Nodes.Add(node); | |
284 symbolDbTreeView_.EndUpdate(); | |
285 if (IsLoadingComplete()) { | |
286 statusLabel_.Text = @"Loading Complete."; | |
287 } | |
288 } else { | |
289 throw new Exception( | |
290 "UpdateTreeView Failed because node was null!"); | |
291 } | |
292 } | |
293 | |
294 #endregion | |
295 } | |
296 } | |
OLD | NEW |