|
1 /* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 package com.nokia.s60tools.crashanalyser.ui.wizards; |
|
19 |
|
20 import org.eclipse.swt.SWT; |
|
21 import org.eclipse.swt.layout.GridData; |
|
22 import org.eclipse.swt.layout.GridLayout; |
|
23 import org.eclipse.swt.widgets.Composite; |
|
24 import org.eclipse.swt.widgets.Label; |
|
25 import org.eclipse.swt.widgets.Table; |
|
26 import org.eclipse.swt.widgets.TableColumn; |
|
27 import org.eclipse.swt.widgets.Button; |
|
28 import org.eclipse.swt.widgets.TableItem; |
|
29 import org.eclipse.swt.browser.*; |
|
30 import org.eclipse.swt.events.*; |
|
31 import org.eclipse.ui.PlatformUI; |
|
32 import com.nokia.s60tools.ui.wizards.S60ToolsWizardPage; |
|
33 import com.nokia.s60tools.crashanalyser.model.*; |
|
34 import com.nokia.s60tools.crashanalyser.resources.HelpContextIDs; |
|
35 import com.nokia.s60tools.crashanalyser.files.*; |
|
36 import java.util.*; |
|
37 import java.text.Collator; |
|
38 import java.util.Locale; |
|
39 import java.text.DateFormat; |
|
40 import java.util.Date; |
|
41 |
|
42 /** |
|
43 * This is the 2nd page in the wizard. This page contains a table from which |
|
44 * user selects the crash files he/she wants to import. |
|
45 */ |
|
46 public class FilesSelectionPage extends S60ToolsWizardPage implements SelectionListener{ |
|
47 |
|
48 Button buttonSelectDeselect; |
|
49 Table tableFiles; |
|
50 TableColumn tableColumnCreated; |
|
51 TableColumn tableColumnType; |
|
52 TableColumn tableColumnRomId; |
|
53 TableColumn tableColumnFile; |
|
54 Label labelFileInfoTitle; |
|
55 Browser browserFileInfo; |
|
56 DecoderEngine engine; |
|
57 Composite composite; |
|
58 List<CrashFileBundle> files = null; |
|
59 String[] filesToBeShown = null; |
|
60 public boolean romIdsMatch = true; |
|
61 static final int TABLE_COLUMN_CREATED = 0; |
|
62 static final int TABLE_COLUMN_TYPE = 1; |
|
63 static final int TABLE_COLUMN_ROMID = 2; |
|
64 static final int TABLE_COLUMN_FILE = 3; |
|
65 static final int TABLE_COLUMN_COUNT = 4; |
|
66 |
|
67 /** |
|
68 * Constructor |
|
69 * @param decEng decoder engine |
|
70 */ |
|
71 public FilesSelectionPage(DecoderEngine decEng, String[] showOnlyTheseFiles) { |
|
72 super(""); |
|
73 |
|
74 setTitle("Select Files"); |
|
75 |
|
76 setDescription("Select crash files to be imported."); |
|
77 |
|
78 // User cannot finish the page before some valid |
|
79 // selection is made. |
|
80 setPageComplete(false); |
|
81 engine = decEng; |
|
82 filesToBeShown = showOnlyTheseFiles; |
|
83 } |
|
84 |
|
85 public void showOnlyTheseFiles(String[] files) { |
|
86 filesToBeShown = files; |
|
87 } |
|
88 |
|
89 @Override |
|
90 public void recalculateButtonStates() { |
|
91 // no implementation needed |
|
92 } |
|
93 |
|
94 @Override |
|
95 public void setInitialFocus() { |
|
96 tableFiles.setFocus(); |
|
97 } |
|
98 |
|
99 /** |
|
100 * Creates all UI controls |
|
101 */ |
|
102 public void createControl(Composite parent) { |
|
103 composite = new Composite(parent, SWT.NULL); |
|
104 |
|
105 // create the desired layout for this wizard page |
|
106 GridLayout gl = new GridLayout(); |
|
107 gl.numColumns = 1; |
|
108 composite.setLayout(gl); |
|
109 |
|
110 // Table |
|
111 tableFiles = new Table(composite, SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION | SWT.CHECK | SWT.V_SCROLL | SWT.H_SCROLL); |
|
112 tableFiles.setLinesVisible (true); |
|
113 tableFiles.setHeaderVisible (true); |
|
114 |
|
115 // Created column |
|
116 tableColumnCreated = new TableColumn (tableFiles, SWT.NONE); |
|
117 tableColumnCreated.setText("Created"); |
|
118 tableColumnCreated.addSelectionListener(this); |
|
119 |
|
120 // Type column |
|
121 tableColumnType = new TableColumn (tableFiles, SWT.NONE); |
|
122 tableColumnType.setText("Type"); |
|
123 tableColumnType.addSelectionListener(this); |
|
124 |
|
125 // ROM ID column |
|
126 tableColumnRomId = new TableColumn (tableFiles, SWT.NONE); |
|
127 tableColumnRomId.setText("ROM ID"); |
|
128 tableColumnRomId.addSelectionListener(this); |
|
129 |
|
130 // File column |
|
131 tableColumnFile = new TableColumn (tableFiles, SWT.NONE); |
|
132 tableColumnFile.setText("File"); |
|
133 tableColumnFile.addSelectionListener(this); |
|
134 |
|
135 autoSizeTableColumns(); |
|
136 |
|
137 GridData treeGD = new GridData(GridData.FILL_BOTH); |
|
138 tableFiles.setLayoutData(treeGD); |
|
139 tableFiles.addSelectionListener(this); |
|
140 |
|
141 // Select/Deselect button |
|
142 buttonSelectDeselect = new Button(composite, SWT.PUSH); |
|
143 buttonSelectDeselect.setText("Select/Unselect"); |
|
144 buttonSelectDeselect.addSelectionListener(this); |
|
145 |
|
146 // File info title |
|
147 labelFileInfoTitle = new Label(composite, SWT.LEFT); |
|
148 labelFileInfoTitle.setText("File Info"); |
|
149 |
|
150 // File info |
|
151 browserFileInfo = new Browser(composite, SWT.BORDER); |
|
152 GridData textGD = new GridData(GridData.FILL_HORIZONTAL); |
|
153 textGD.heightHint = 150; |
|
154 browserFileInfo.setLayoutData(textGD); |
|
155 browserFileInfo.setText(""); |
|
156 |
|
157 setHelps(); |
|
158 |
|
159 setInitialFocus(); |
|
160 |
|
161 setControl(composite); |
|
162 |
|
163 updateButtons(); |
|
164 } |
|
165 |
|
166 /** |
|
167 * Autos sizes all table columns |
|
168 */ |
|
169 void autoSizeTableColumns() { |
|
170 for (int i = 0; i < TABLE_COLUMN_COUNT; i++) { |
|
171 tableFiles.getColumn(i).pack(); |
|
172 } |
|
173 } |
|
174 |
|
175 /** |
|
176 * Loads the table with files given by decoder engine |
|
177 */ |
|
178 public void loadTable() { |
|
179 tableFiles.removeAll(); |
|
180 files = engine.getCrashFiles(); |
|
181 if (files == null || files.size() < 1) { |
|
182 setErrorMessage("No crash files found."); |
|
183 } else { |
|
184 for (int i = 0; i < files.size(); i++) { |
|
185 CrashFileBundle file = files.get(i); |
|
186 String fileType = ""; |
|
187 String fileName = ""; |
|
188 // summary xml file |
|
189 if (file.isPartiallyDecoded()) { |
|
190 SummaryFile summaryFile = file.getSummaryFile(); |
|
191 fileType = summaryFile.getSourceFileType(); |
|
192 fileName = summaryFile.getSourceFileName(); |
|
193 // .crashxml file |
|
194 } else { |
|
195 CrashFile crashfile = file.getCrashFile(); |
|
196 fileType = crashfile.getSourceFileType(); |
|
197 fileName = crashfile.getFileName(); |
|
198 } |
|
199 // if user has drag&dropped multiple files, we have scanned the whole |
|
200 // folder, but we should show only the dragged ones |
|
201 if (!shouldCrashFileBeShown(fileName)) |
|
202 continue; |
|
203 TableItem item = new TableItem (tableFiles, SWT.NONE); |
|
204 item.setText(0, file.getTime()); |
|
205 item.setText(1, fileType); |
|
206 item.setText(2, file.getRomId()); |
|
207 item.setText(3, fileName); |
|
208 item.setData(file); |
|
209 item.setChecked(true); |
|
210 } |
|
211 autoSizeTableColumns(); |
|
212 } |
|
213 browserFileInfo.setText(""); |
|
214 |
|
215 if (tableFiles.getItemCount() > 0) { |
|
216 tableFiles.select(0); |
|
217 showFileInfo(); |
|
218 } |
|
219 } |
|
220 |
|
221 /** |
|
222 * Checks whether given crash file should be shown in table. if user has drag&dropped |
|
223 * multiple files, we have scanned the whole folder, but we should show only the dragged ones. |
|
224 * @param fileName file to be checked |
|
225 * @return true if file should be shown, false if not |
|
226 */ |
|
227 boolean shouldCrashFileBeShown(String fileName) { |
|
228 if (filesToBeShown != null && filesToBeShown.length > 0) { |
|
229 for (int i = 0; i < filesToBeShown.length; i++) { |
|
230 if (fileName.equalsIgnoreCase(FileOperations.getFileNameWithExtension(filesToBeShown[i]))) |
|
231 return true; |
|
232 } |
|
233 return false; |
|
234 |
|
235 } else { |
|
236 return true; |
|
237 } |
|
238 } |
|
239 |
|
240 public void widgetDefaultSelected(SelectionEvent e) { |
|
241 // no implementation needed |
|
242 } |
|
243 |
|
244 public void widgetSelected(SelectionEvent e) { |
|
245 // Select/Unselect button pressed |
|
246 if (e.widget == buttonSelectDeselect) { |
|
247 TableItem[] items = tableFiles.getItems(); |
|
248 if (items != null) { |
|
249 boolean checkAll = true; |
|
250 // check whether items needs to be checked or unchecked |
|
251 for (int i = 0; i < items.length; i++) { |
|
252 if (items[i].getChecked()) { |
|
253 checkAll = false; |
|
254 break; |
|
255 } |
|
256 } |
|
257 |
|
258 // check/uncheck all items |
|
259 for (int i = 0; i < items.length; i++) |
|
260 items[i].setChecked(checkAll); |
|
261 } |
|
262 showFileInfo(); |
|
263 updateButtons(); |
|
264 |
|
265 // table item selected/checked/unchecked |
|
266 } else if (e.widget == tableFiles) { |
|
267 // item was checked/unchecked |
|
268 if (e.detail == SWT.CHECK) { |
|
269 tableFiles.setSelection((TableItem)e.item); |
|
270 updateButtons(); |
|
271 } |
|
272 showFileInfo(); |
|
273 |
|
274 // table column presses -> sort |
|
275 } else if (e.widget == tableColumnCreated ) { |
|
276 sortTableByColumn(TABLE_COLUMN_CREATED, tableColumnCreated); |
|
277 } else if (e.widget == tableColumnType) { |
|
278 sortTableByColumn(TABLE_COLUMN_TYPE, tableColumnType); |
|
279 } else if (e.widget == tableColumnRomId) { |
|
280 sortTableByColumn(TABLE_COLUMN_ROMID, tableColumnRomId); |
|
281 } else if (e.widget == tableColumnFile) { |
|
282 sortTableByColumn(TABLE_COLUMN_FILE, tableColumnFile); |
|
283 } |
|
284 } |
|
285 |
|
286 /** |
|
287 * Sorts table by given column number |
|
288 * @param column column number |
|
289 * @param col column item |
|
290 */ |
|
291 void sortTableByColumn(int column, TableColumn col) { |
|
292 TableItem[] items = tableFiles.getItems(); |
|
293 Collator collator = Collator.getInstance(Locale.getDefault()); |
|
294 |
|
295 TableColumn sortColumn = tableFiles.getSortColumn(); |
|
296 |
|
297 // column is sorted for the "first time" or column is sorted UP. Sort column DOWN. |
|
298 if (sortColumn == null || !col.equals(sortColumn) || tableFiles.getSortDirection() == SWT.UP) { |
|
299 for (int i = 1; i < items.length; i++) { |
|
300 String value1 = items[i].getText(column); |
|
301 for (int j = 0; j < i; j++) { |
|
302 String value2 = items[j].getText(column); |
|
303 // time compare |
|
304 if (column == TABLE_COLUMN_CREATED) { |
|
305 try { |
|
306 DateFormat date = DateFormat.getInstance(); |
|
307 Date d1 = date.parse(value1); |
|
308 Date d2 = date.parse(value2); |
|
309 if (d1 != null && d2 != null && d1.compareTo(d2) < 0) { |
|
310 boolean checked = items[i].getChecked(); |
|
311 String[] values = { items[i].getText(0), items[i].getText(1), items[i].getText(2), items[i].getText(3)}; |
|
312 items[i].dispose(); |
|
313 TableItem item = new TableItem(tableFiles, SWT.NONE, j); |
|
314 item.setText(values); |
|
315 item.setChecked(checked); |
|
316 items = tableFiles.getItems(); |
|
317 break; |
|
318 } |
|
319 } catch (Exception e) { |
|
320 e.printStackTrace(); |
|
321 } |
|
322 // string compare |
|
323 } else { |
|
324 if (collator.compare(value1, value2) < 0) { |
|
325 boolean checked = items[i].getChecked(); |
|
326 String[] values = { items[i].getText(0), items[i].getText(1), items[i].getText(2), items[i].getText(3)}; |
|
327 items[i].dispose(); |
|
328 TableItem item = new TableItem(tableFiles, SWT.NONE, j); |
|
329 item.setText(values); |
|
330 item.setChecked(checked); |
|
331 items = tableFiles.getItems(); |
|
332 break; |
|
333 } |
|
334 } |
|
335 } |
|
336 } |
|
337 tableFiles.setSortColumn(col); |
|
338 tableFiles.setSortDirection(SWT.DOWN); |
|
339 |
|
340 // Reverse rows |
|
341 } else { |
|
342 int index = items.length-1; |
|
343 for (int i = 0; i < items.length-1; i++) { |
|
344 boolean checked = items[index].getChecked(); |
|
345 String[] values = { items[index].getText(0), items[index].getText(1), items[index].getText(2), items[index].getText(3)}; |
|
346 items[index].dispose(); |
|
347 TableItem item = new TableItem(tableFiles, SWT.NONE, i); |
|
348 item.setText(values); |
|
349 item.setChecked(checked); |
|
350 items = tableFiles.getItems(); |
|
351 } |
|
352 |
|
353 tableFiles.setSortColumn(col); |
|
354 tableFiles.setSortDirection(SWT.UP); |
|
355 } |
|
356 } |
|
357 |
|
358 /** |
|
359 * Updates next, finish button states |
|
360 */ |
|
361 void updateButtons() { |
|
362 try { |
|
363 getWizard().getContainer().updateButtons(); |
|
364 } catch (Exception E) { |
|
365 } |
|
366 } |
|
367 |
|
368 /** |
|
369 * Show information about the currently selected file |
|
370 */ |
|
371 void showFileInfo() { |
|
372 int selected = tableFiles.getSelectionIndex(); |
|
373 if (selected >= 0) { |
|
374 CrashFileBundle cfb = (CrashFileBundle)tableFiles.getItem(selected).getData(); |
|
375 browserFileInfo.setText(HtmlFormatter.formatHtmlStyle(labelFileInfoTitle.getFont(), |
|
376 cfb.getDescription(false))); |
|
377 } else { |
|
378 browserFileInfo.setText(""); |
|
379 } |
|
380 } |
|
381 |
|
382 /** |
|
383 * Checks whether we can press Next button |
|
384 */ |
|
385 public boolean canFlipToNextPage() { |
|
386 try { |
|
387 // decoder engine contains no files (shouldn't happen) |
|
388 if (files == null || files.size() < 1) |
|
389 return false; |
|
390 |
|
391 TableItem[] items = tableFiles.getItems(); |
|
392 // no items in table (shouldn't happen) |
|
393 if (items == null) { |
|
394 return false; |
|
395 // table contains items |
|
396 } else { |
|
397 String romId = ""; |
|
398 boolean selectedFiles = false; |
|
399 boolean hasMultipleRomIds = false; |
|
400 // check whether user is trying to import files which |
|
401 // have different ROM IDs |
|
402 for (int i = 0; i < items.length; i++) { |
|
403 CrashFileBundle file = (CrashFileBundle)items[i].getData(); |
|
404 if (!items[i].getChecked() || file == null) |
|
405 continue; |
|
406 |
|
407 selectedFiles = true; |
|
408 |
|
409 // ignore ROM ID of .crashxml file |
|
410 if (file.isFullyDecoded()) |
|
411 continue; |
|
412 |
|
413 //ignore if file has no rom id |
|
414 if ("".equals(file.getRomId())) |
|
415 continue; |
|
416 |
|
417 if (!"".equals(romId) && !file.getRomId().equalsIgnoreCase(romId)) { |
|
418 hasMultipleRomIds = true; |
|
419 } |
|
420 romId = file.getRomId(); |
|
421 } |
|
422 |
|
423 // don't allow to proceed when multiple different ROM ID file are selected |
|
424 if (hasMultipleRomIds) { |
|
425 this.setErrorMessage("ROM IDs of selected files do not match. Please select only files which have same ROM IDs."); |
|
426 return false; |
|
427 } else { |
|
428 this.setErrorMessage(null); |
|
429 } |
|
430 |
|
431 // no checked files |
|
432 if (!selectedFiles) |
|
433 return false; |
|
434 } |
|
435 } catch (Exception e) { |
|
436 e.printStackTrace(); |
|
437 return false; |
|
438 } |
|
439 return true; |
|
440 } |
|
441 |
|
442 /** |
|
443 * Checks whether Finish button can be enabled. Finish button can be |
|
444 * enabled if user is importing only already decoded files (.crashxml files). |
|
445 * |
|
446 * @return true if Finish button can be enable, false if not |
|
447 */ |
|
448 public boolean canFinish() { |
|
449 try { |
|
450 // if no files in this page (shouldn't happen) |
|
451 if (files == null || files.size() < 1) |
|
452 return false; |
|
453 |
|
454 TableItem[] items = tableFiles.getItems(); |
|
455 // if no files in table (shouldn't happen) |
|
456 if (items == null) { |
|
457 return false; |
|
458 } else { |
|
459 boolean hasAnalyzedFiles = false; |
|
460 boolean hasUndecodedFiles = false; |
|
461 // go through all checked files in the table |
|
462 for (int i = 0; i < items.length; i++) { |
|
463 if (!items[i].getChecked()) |
|
464 continue; |
|
465 |
|
466 CrashFileBundle file = (CrashFileBundle)items[i].getData(); |
|
467 if (file != null) { |
|
468 if (file.isPartiallyDecoded()) { |
|
469 hasUndecodedFiles = true; |
|
470 } else { |
|
471 hasAnalyzedFiles = true; |
|
472 } |
|
473 } |
|
474 } |
|
475 |
|
476 // only .crashxml files are selected, we can show Finish button |
|
477 if (hasAnalyzedFiles && !hasUndecodedFiles) |
|
478 return true; |
|
479 } |
|
480 } catch (Exception e) { |
|
481 e.printStackTrace(); |
|
482 } |
|
483 return false; |
|
484 } |
|
485 |
|
486 /** |
|
487 * Checks whether only .crashxml files are selected in the table |
|
488 * @return true if only .crashxml files are selected, false if not |
|
489 */ |
|
490 public boolean onlyCrashxmlFilesSelected() { |
|
491 try { |
|
492 // if no files in this page (shouldn't happen) |
|
493 if (files == null || files.size() < 1) |
|
494 return false; |
|
495 |
|
496 TableItem[] items = tableFiles.getItems(); |
|
497 // if no files in table (shouldn't happen) |
|
498 if (items == null) { |
|
499 return false; |
|
500 } else { |
|
501 boolean onlyCrashxmlFiles = true; |
|
502 // go through all checked files in the table |
|
503 for (int i = 0; i < items.length; i++) { |
|
504 if (!items[i].getChecked()) |
|
505 continue; |
|
506 CrashFileBundle file = (CrashFileBundle)items[i].getData(); |
|
507 if (file.isPartiallyDecoded()) { |
|
508 onlyCrashxmlFiles = false; |
|
509 break; |
|
510 } |
|
511 } |
|
512 |
|
513 if (onlyCrashxmlFiles) |
|
514 return true; |
|
515 } |
|
516 } catch (Exception e) { |
|
517 e.printStackTrace(); |
|
518 return false; |
|
519 } |
|
520 return false; |
|
521 } |
|
522 |
|
523 /** |
|
524 * Returns indexes of those Crash files which are selected (checked) in the table |
|
525 * @return indexes of those Crash files which are selected (checked) in the table |
|
526 */ |
|
527 public List<Integer> getFileIndexes() { |
|
528 List<Integer> indexes = new ArrayList<Integer>(); |
|
529 |
|
530 TableItem[] items = tableFiles.getItems(); |
|
531 // if no files in table (shouldn't happen) |
|
532 if (items == null) { |
|
533 return null; |
|
534 } else { |
|
535 // go through all checked files in the table |
|
536 for (int i = 0; i < items.length; i++) { |
|
537 if (items[i].getChecked()) |
|
538 indexes.add(i); |
|
539 } |
|
540 } |
|
541 |
|
542 if (indexes.isEmpty()) { |
|
543 return null; |
|
544 } else { |
|
545 return indexes; |
|
546 } |
|
547 } |
|
548 |
|
549 /** |
|
550 * Sets this page's context sensitive helps |
|
551 * |
|
552 */ |
|
553 protected void setHelps() { |
|
554 PlatformUI.getWorkbench().getHelpSystem().setHelp(tableFiles, |
|
555 HelpContextIDs.CRASH_ANALYSER_HELP_IMPORT_CRASH_FILES); |
|
556 |
|
557 PlatformUI.getWorkbench().getHelpSystem().setHelp(browserFileInfo, |
|
558 HelpContextIDs.CRASH_ANALYSER_HELP_IMPORT_CRASH_FILES); |
|
559 |
|
560 PlatformUI.getWorkbench().getHelpSystem().setHelp(buttonSelectDeselect, |
|
561 HelpContextIDs.CRASH_ANALYSER_HELP_IMPORT_CRASH_FILES); |
|
562 } |
|
563 } |