Updated the order of imports in the source files of simulator plugins.
[platform/upstream/iotivity.git] / service / simulator / java / eclipse-plugin / ClientControllerPlugin / src / oic / simulator / clientcontroller / view / LogView.java
1 /*
2  * Copyright 2015 Samsung Electronics All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package oic.simulator.clientcontroller.view;
18
19 import org.eclipse.jface.action.Action;
20 import org.eclipse.jface.action.IAction;
21 import org.eclipse.jface.action.IContributionItem;
22 import org.eclipse.jface.action.IMenuManager;
23 import org.eclipse.jface.action.IToolBarManager;
24 import org.eclipse.jface.action.MenuManager;
25 import org.eclipse.jface.action.Separator;
26 import org.eclipse.jface.dialogs.MessageDialog;
27 import org.eclipse.jface.resource.ImageDescriptor;
28 import org.eclipse.jface.viewers.DoubleClickEvent;
29 import org.eclipse.jface.viewers.IDoubleClickListener;
30 import org.eclipse.jface.viewers.ISelectionChangedListener;
31 import org.eclipse.jface.viewers.IStructuredSelection;
32 import org.eclipse.jface.viewers.SelectionChangedEvent;
33 import org.eclipse.jface.viewers.StructuredSelection;
34 import org.eclipse.jface.viewers.TreeViewer;
35 import org.eclipse.jface.viewers.Viewer;
36 import org.eclipse.jface.viewers.ViewerComparator;
37 import org.eclipse.jface.window.Window;
38 import org.eclipse.swt.SWT;
39 import org.eclipse.swt.events.KeyEvent;
40 import org.eclipse.swt.events.KeyListener;
41 import org.eclipse.swt.events.SelectionAdapter;
42 import org.eclipse.swt.events.SelectionEvent;
43 import org.eclipse.swt.layout.GridData;
44 import org.eclipse.swt.widgets.Composite;
45 import org.eclipse.swt.widgets.Display;
46 import org.eclipse.swt.widgets.FileDialog;
47 import org.eclipse.swt.widgets.Text;
48 import org.eclipse.swt.widgets.Tree;
49 import org.eclipse.swt.widgets.TreeColumn;
50 import org.eclipse.swt.widgets.TreeItem;
51 import org.eclipse.ui.IActionBars;
52 import org.eclipse.ui.IWorkbenchActionConstants;
53 import org.eclipse.ui.IWorkbenchPage;
54 import org.eclipse.ui.dialogs.FilteredTree;
55 import org.eclipse.ui.dialogs.PatternFilter;
56 import org.eclipse.ui.part.ViewPart;
57
58 import java.io.BufferedWriter;
59 import java.io.FileWriter;
60 import java.io.IOException;
61 import java.text.DateFormat;
62 import java.text.SimpleDateFormat;
63 import java.util.Date;
64 import java.util.HashMap;
65 import java.util.List;
66
67 import org.oic.simulator.ILogger.Level;
68
69 import oic.simulator.clientcontroller.Activator;
70 import oic.simulator.clientcontroller.listener.ILogUIListener;
71 import oic.simulator.clientcontroller.manager.LogManager;
72 import oic.simulator.clientcontroller.utils.Constants;
73 import oic.simulator.clientcontroller.view.dialogs.FilterDialog;
74 import oic.simulator.clientcontroller.view.dialogs.LogDetailsDialog;
75 import oic.simulator.logger.LogContentProvider;
76 import oic.simulator.logger.LogEntry;
77 import oic.simulator.logger.LogLabelProvider;
78
79 /**
80  * This class manages and shows the log view in the perspective.
81  */
82 public class LogView extends ViewPart {
83
84     public static final String        VIEW_ID              = "oic.simulator.clientcontroller.view.log";
85
86     private LogManager                logManager;
87     private ILogUIListener            logListener;
88
89     private LogContentProvider        treeContentProvider;
90
91     private FilteredTree              tree;
92     private TreeColumn                severityColumn;
93     private TreeColumn                dateColumn;
94     private TreeColumn                messageColumn;
95
96     private IAction                   exportLogAction;
97     private IAction                   clearLogAction;
98     private IAction                   deleteLogAction;
99     private IAction                   scrollLockAction;
100     private IAction                   logDetailsAction;
101     private IAction                   filterAction;
102     private IAction                   activateViewAction;
103     private IAction                   showTextFilter;
104     private IContributionItem         groupByAction;
105
106     private HashMap<Integer, Boolean> shownSeverities      = new HashMap<Integer, Boolean>();
107
108     private boolean                   activateOnChange     = false;
109
110     private boolean                   hideTextFilter       = false;
111
112     private boolean                   scrollLockDisabled;
113
114     public static final int           ORDER_BY_TIME        = 0;
115     public static final int           ORDER_BY_SEVERITY    = 1;
116     public static final int           ORDER_BY_MESSAGE     = 2;
117
118     int                               sortCandidate        = ORDER_BY_TIME;
119
120     SortAction                        sortByTimeAction     = new SortAction(
121                                                                    "Order by Time",
122                                                                    ORDER_BY_TIME);
123     SortAction                        sortBySeverityAction = new SortAction(
124                                                                    "Order by Severity",
125                                                                    ORDER_BY_SEVERITY);
126     SortAction                        sortByMessageAction  = new SortAction(
127                                                                    "Order by Message",
128                                                                    ORDER_BY_MESSAGE);
129
130     private ViewerComparator          dateComparator;
131     private ViewerComparator          severityComparator;
132     private ViewerComparator          messageComparator;
133
134     private TreeColumn                sortColumn           = null;
135     private static int                DOWN                 = 1;
136     private static int                UP                   = -1;
137     private int                       sortDirection        = DOWN;
138
139     public LogView() {
140
141         logListener = new ILogUIListener() {
142
143             @Override
144             public void logChanged(final List<LogEntry> entry) {
145                 Display.getDefault().asyncExec(new Runnable() {
146
147                     @Override
148                     public void run() {
149                         TreeViewer viewer = tree.getViewer();
150                         if (viewer.getControl().isDisposed()) {
151                             return;
152                         }
153                         viewer.setInput(entry);
154                         updateTree(false);
155                     }
156                 });
157             }
158
159             @Override
160             public void logAdded(final LogEntry added) {
161                 Display.getDefault().asyncExec(new Runnable() {
162
163                     @Override
164                     public void run() {
165                         TreeViewer viewer = tree.getViewer();
166                         if (viewer.getControl().isDisposed()) {
167                             return;
168                         }
169                         LogContentProvider provider = (LogContentProvider) viewer
170                                 .getContentProvider();
171                         provider.addLog(added);
172                         tree.getViewer().add(viewer.getInput(), added);
173                         @SuppressWarnings("unchecked")
174                         List<LogEntry> input = (List<LogEntry>) viewer
175                                 .getInput();
176                         if (input.size() > Constants.LOG_SIZE) {
177                             viewer.remove(viewer.getInput(), 0);
178                         }
179                         updateTree(true);
180                     }
181                 });
182             }
183
184             private void updateTree(boolean needscroll) {
185                 if (activateOnChange) {
186                     IWorkbenchPage page = Activator.getDefault().getWorkbench()
187                             .getActiveWorkbenchWindow().getActivePage();
188                     if (page != null) {
189                         page.bringToTop(LogView.this);
190                     }
191                 }
192                 if (scrollLockDisabled && needscroll) {
193                     Tree tree2 = tree.getViewer().getTree();
194                     if (tree2.getItemCount() > 0) {
195                         TreeItem item = tree2.getItem(tree2.getItemCount() - 1);
196                         tree2.setTopItem(item);
197                         deleteLogAction.setEnabled(true);
198                     }
199                 }
200             }
201         };
202
203         logManager = Activator.getDefault().getLogManager();
204
205         // Initially state of scroll lock
206         scrollLockDisabled = true;
207     }
208
209     @Override
210     public void createPartControl(Composite parent) {
211         PatternFilter filter = new PatternFilter() {
212
213             DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
214
215             @Override
216             protected boolean isLeafMatch(Viewer viewer, Object element) {
217                 if (element instanceof LogEntry) {
218                     LogEntry logEntry = (LogEntry) element;
219                     String severity = LogManager.getSeverityName(logEntry
220                             .getSeverity());
221                     String date = dateFormat.format(logEntry.getDate());
222                     String message = logEntry.getMessage();
223                     return wordMatches(severity) || wordMatches(date)
224                             || wordMatches(message);
225                 }
226                 return false;
227             }
228         };
229         filter.setIncludeLeadingWildcard(true);
230         tree = new FilteredTree(parent, SWT.SINGLE | SWT.H_SCROLL
231                 | SWT.V_SCROLL | SWT.FULL_SELECTION, filter, true);
232
233         setupFilteredTree();
234
235         createColumnComparators();
236
237         createActions();
238
239         setDefaultShownSeverities();
240
241         IActionBars actionBars = getViewSite().getActionBars();
242         IToolBarManager toolBarManager = actionBars.getToolBarManager();
243         toolBarManager.add(exportLogAction);
244         toolBarManager.add(clearLogAction);
245         toolBarManager.add(deleteLogAction);
246         toolBarManager.add(scrollLockAction);
247         toolBarManager
248                 .add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
249
250         IMenuManager mgr = actionBars.getMenuManager();
251         mgr.add(groupByAction);
252         mgr.add(new Separator());
253         mgr.add(filterAction);
254         mgr.add(new Separator());
255         mgr.add(activateViewAction);
256         mgr.add(showTextFilter);
257
258         addManagerListeners();
259
260         if (sortCandidate == ORDER_BY_TIME) {
261             sortByTimeAction.run();
262         } else if (sortCandidate == ORDER_BY_SEVERITY) {
263             sortBySeverityAction.run();
264         } else { // order_selected == ORDER_BY_NONE
265             sortByMessageAction.run();
266         }
267
268     }
269
270     private void setupFilteredTree() {
271         tree.setLayoutData(new GridData(GridData.FILL_BOTH));
272         final Tree innerTree = tree.getViewer().getTree();
273         innerTree.setLinesVisible(true);
274
275         severityColumn = new TreeColumn(innerTree, SWT.LEFT);
276         severityColumn.setText("Severity");
277         severityColumn.setWidth(110);
278         severityColumn.addSelectionListener(new SelectionAdapter() {
279
280             @Override
281             public void widgetSelected(SelectionEvent e) {
282                 sortBySeverityAction.run();
283             }
284         });
285         dateColumn = new TreeColumn(innerTree, SWT.LEFT);
286         dateColumn.setText("Time");
287         dateColumn.setWidth(110);
288         dateColumn.addSelectionListener(new SelectionAdapter() {
289
290             @Override
291             public void widgetSelected(SelectionEvent e) {
292                 sortByTimeAction.run();
293             }
294         });
295         messageColumn = new TreeColumn(innerTree, SWT.LEFT);
296         messageColumn.setText("Message");
297         messageColumn.setWidth(180);
298         messageColumn.addSelectionListener(new SelectionAdapter() {
299             @Override
300             public void widgetSelected(SelectionEvent e) {
301                 sortByMessageAction.run();
302             }
303         });
304
305         innerTree.setHeaderVisible(true);
306
307         treeContentProvider = new LogContentProvider();
308
309         tree.getViewer().setContentProvider(treeContentProvider);
310         tree.getViewer().setLabelProvider(new LogLabelProvider());
311
312         tree.getViewer().setInput(logManager.getLogEntries());
313
314         tree.getViewer().addSelectionChangedListener(
315                 new ISelectionChangedListener() {
316
317                     @Override
318                     public void selectionChanged(SelectionChangedEvent event) {
319                         deleteLogAction.setEnabled(!tree.getViewer()
320                                 .getSelection().isEmpty());
321                         logDetailsAction.setEnabled(!tree.getViewer()
322                                 .getSelection().isEmpty());
323                     }
324                 });
325
326         tree.getViewer().getTree().addKeyListener(new KeyListener() {
327
328             @Override
329             public void keyReleased(KeyEvent e) {
330             }
331
332             @Override
333             public void keyPressed(KeyEvent e) {
334                 if (e.character == (char) 127) { // If delete key is pressed
335                     if (deleteLogAction.isEnabled()) {
336                         deleteLogAction.run();
337                     }
338                 }
339             }
340         });
341
342         tree.getViewer().addDoubleClickListener(new IDoubleClickListener() {
343
344             @Override
345             public void doubleClick(DoubleClickEvent event) {
346                 logDetailsAction.run();
347             }
348         });
349     }
350
351     private void createColumnComparators() {
352         dateComparator = new ViewerComparator() {
353
354             @Override
355             public int compare(Viewer viewer, Object e1, Object e2) {
356                 LogEntry l1 = (LogEntry) e1;
357                 LogEntry l2 = (LogEntry) e2;
358                 return l1.getDate().compareTo(l2.getDate()) * sortDirection;
359             }
360         };
361
362         severityComparator = new ViewerComparator() {
363
364             @Override
365             public int compare(Viewer viewer, Object e1, Object e2) {
366                 LogEntry l1 = (LogEntry) e1;
367                 LogEntry l2 = (LogEntry) e2;
368                 if (l1.getSeverity() < l2.getSeverity()) {
369                     return -1 * sortDirection;
370                 }
371                 if (l1.getSeverity() > l2.getSeverity()) {
372                     return 1 * sortDirection;
373                 }
374                 return 0;
375             }
376         };
377
378         messageComparator = new ViewerComparator() {
379
380             @Override
381             public int compare(Viewer viewer, Object e1, Object e2) {
382                 LogEntry l1 = (LogEntry) e1;
383                 LogEntry l2 = (LogEntry) e2;
384                 return l1.getMessage().compareTo(l2.getMessage())
385                         * sortDirection;
386             }
387         };
388
389     }
390
391     private void setDefaultShownSeverities() {
392         shownSeverities.put(Level.INFO.ordinal(), true);
393         shownSeverities.put(Level.DEBUG.ordinal(), true);
394         shownSeverities.put(Level.WARNING.ordinal(), true);
395         shownSeverities.put(Level.ERROR.ordinal(), true);
396     }
397
398     private void addManagerListeners() {
399         logManager.addLogListener(logListener);
400         logManager.applyFilter(shownSeverities);
401     }
402
403     private void createActions() {
404         exportLogAction = createExportLogAction();
405         clearLogAction = createClearLogAction();
406         deleteLogAction = createDeleteLogAction();
407         scrollLockAction = createScrollLockAction();
408         logDetailsAction = createLogDetailsAction();
409
410         filterAction = createFilterAction();
411         activateViewAction = createActivateViewAction();
412         showTextFilter = createShowTextFilter();
413         groupByAction = createGroupByAction();
414     }
415
416     private IAction createExportLogAction() {
417         Action action = new Action("Export log") {
418             @Override
419             public void run() {
420                 FileDialog fd = new FileDialog(Display.getDefault()
421                         .getActiveShell(), SWT.SAVE);
422                 fd.setOverwrite(true);
423                 fd.setFileName("OIC_Simulator_ServerLog.log");
424                 fd.setFilterExtensions(Constants.SAVE_LOG_FILTER_EXTENSIONS);
425                 String name = fd.open();
426                 List<LogEntry> logEntries = logManager.getLogEntries();
427                 StringBuilder sb = new StringBuilder();
428                 for (LogEntry entry : logEntries) {
429                     sb.append(entry.toString());
430                 }
431                 String data = sb.toString();
432                 BufferedWriter out = null;
433                 try {
434                     out = new BufferedWriter(new FileWriter(name));
435                     out.write(data);
436                 } catch (IOException e) {
437                     e.printStackTrace();
438                     MessageDialog.openError(
439                             Display.getDefault().getActiveShell(),
440                             "Export error",
441                             "Could not export log. IO exception: "
442                                     + e.getMessage());
443                 } finally {
444                     try {
445                         if (null != out) {
446                             out.close();
447                         }
448                     } catch (IOException e) {
449                         Activator
450                                 .getDefault()
451                                 .getLogManager()
452                                 .log(Level.ERROR.ordinal(),
453                                         new Date(),
454                                         "[" + e.getClass().getSimpleName()
455                                                 + "]" + e.getMessage());
456                     }
457                 }
458             }
459         };
460         action.setToolTipText("Export log");
461
462         action.setImageDescriptor(ImageDescriptor.createFromFile(
463                 this.getClass(), "/icons/export_log_e.gif"));
464         action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
465                 this.getClass(), "/icons/export_log_d.gif"));
466         action.setEnabled(true);
467
468         return action;
469     }
470
471     private IAction createClearLogAction() {
472         Action action = new Action("Clear log") {
473
474             @Override
475             public void run() {
476                 logManager.clearLog();
477             }
478         };
479         action.setToolTipText("Clear log");
480
481         action.setImageDescriptor(ImageDescriptor.createFromFile(
482                 this.getClass(), "/icons/clear_e.gif"));
483         action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
484                 this.getClass(), "/icons/clear_d.gif"));
485         action.setEnabled(true);
486         return action;
487     }
488
489     private IAction createDeleteLogAction() {
490         Action action = new Action("Delete log entry") {
491
492             @Override
493             @SuppressWarnings("unchecked")
494             public void run() {
495                 IStructuredSelection selection = (IStructuredSelection) tree
496                         .getViewer().getSelection();
497                 List<LogEntry> entries = (List<LogEntry>) tree.getViewer()
498                         .getInput();
499                 LogEntry selectedEntry = (LogEntry) selection.getFirstElement();
500                 if (null != selectedEntry) {
501                     LogEntry toBeShownEntry = null;
502                     for (LogEntry entry : entries) {
503                         if (entry.equals(selectedEntry)) {
504                             int size = entries.size();
505                             int index = entries.indexOf(selectedEntry);
506                             if (index + 1 < size) {
507                                 toBeShownEntry = entries.get(index + 1);
508                             } else if (index > 0) {
509                                 toBeShownEntry = entries.get(index - 1);
510                             }
511                             break;
512                         }
513                     }
514                     logManager.removeEntry(selectedEntry);
515                     if (null != toBeShownEntry) {
516                         tree.getViewer().setSelection(
517                                 new StructuredSelection(toBeShownEntry));
518                     }
519                 }
520             }
521         };
522         action.setToolTipText("Delete log entry");
523         action.setImageDescriptor(ImageDescriptor.createFromFile(
524                 this.getClass(), "/icons/delete_e.gif"));
525         action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
526                 this.getClass(), "/icons/delete_d.gif"));
527         action.setEnabled(false);
528         return action;
529     }
530
531     private IAction createScrollLockAction() {
532         Action action = new Action("Scroll lock") {
533
534             @Override
535             public void run() {
536                 scrollLockDisabled = !this.isChecked();
537             };
538
539             @Override
540             public int getStyle() {
541                 return IAction.AS_CHECK_BOX;
542             }
543         };
544         action.setToolTipText("Scroll lock");
545         action.setImageDescriptor(ImageDescriptor.createFromFile(
546                 this.getClass(), "/icons/lock_e.gif"));
547         action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
548                 this.getClass(), "/icons/lock_d.gif"));
549         action.setEnabled(true);
550         return action;
551     }
552
553     private IAction createLogDetailsAction() {
554         Action action = new Action("Details...") {
555
556             @Override
557             public void run() {
558                 Display.getDefault().asyncExec(new Runnable() {
559
560                     @Override
561                     public void run() {
562                         LogEntry x = (LogEntry) ((IStructuredSelection) tree
563                                 .getViewer().getSelection()).getFirstElement();
564
565                         new LogDetailsDialog(Display.getDefault()
566                                 .getActiveShell(), LogManager.getSeverityName(x
567                                 .getSeverity()), LogManager.getSeverityIcon(x
568                                 .getSeverity()), x.getDate(), x.getMessage())
569                                 .open();
570                     }
571                 });
572             }
573         };
574         action.setToolTipText("Details...");
575         action.setImageDescriptor(ImageDescriptor.createFromFile(
576                 this.getClass(), "/icons/log_details_e.gif"));
577         action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
578                 this.getClass(), "/icons/log_details_e.gif"));
579         action.setEnabled(false);
580         return action;
581     }
582
583     private IAction createFilterAction() {
584         Action action = new Action("Filters ...") {
585
586             @Override
587             public void run() {
588                 FilterDialog fd = new FilterDialog(Display.getDefault()
589                         .getActiveShell(), shownSeverities);
590                 if (fd.open() == Window.OK) {
591                     logManager.applyFilter(shownSeverities);
592                 }
593                 tree.getViewer().refresh();
594             }
595         };
596         action.setToolTipText("Filters ...");
597
598         action.setImageDescriptor(ImageDescriptor.createFromFile(
599                 this.getClass(), "/icons/filter_e.gif"));
600         action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
601                 this.getClass(), "/icons/filter_d.gif"));
602         action.setEnabled(true);
603         return action;
604     }
605
606     private IAction createActivateViewAction() {
607         Action action = new Action("Activate view on new events",
608                 IAction.AS_CHECK_BOX) {
609
610             @Override
611             public void run() {
612                 activateOnChange = this.isChecked();
613             }
614         };
615         action.setChecked(activateOnChange);
616         action.setToolTipText("Activate view on new events");
617
618         action.setImageDescriptor(ImageDescriptor.createFromFile(
619                 this.getClass(), "/icons/prop_e.gif"));
620         action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
621                 this.getClass(), "/icons/prop_d.gif"));
622         action.setEnabled(true);
623         return action;
624     }
625
626     private IAction createShowTextFilter() {
627         Action action = new Action("Show text filter", IAction.AS_CHECK_BOX) {
628
629             @Override
630             public void run() {
631                 Text filterControl = tree.getFilterControl();
632                 Composite filterComposite = filterControl.getParent();
633                 GridData gd = (GridData) filterComposite.getLayoutData();
634                 boolean visible = isChecked();
635                 gd.exclude = !visible;
636                 filterComposite.setVisible(visible);
637                 filterControl.setText("");
638                 if (visible) {
639                     filterControl.selectAll();
640                     setFocus();
641                 }
642                 tree.layout(false);
643                 hideTextFilter = !visible;
644             }
645         };
646         action.setToolTipText("Show text filter");
647
648         action.setImageDescriptor(ImageDescriptor.createFromFile(
649                 this.getClass(), "/icons/tree_mode_e.gif"));
650         action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
651                 this.getClass(), "/icons/tree_mode_d.gif"));
652         action.setEnabled(true);
653         action.setChecked(!hideTextFilter);
654         if (hideTextFilter) {
655             action.run();
656         }
657         return action;
658     }
659
660     private IContributionItem createGroupByAction() {
661         IMenuManager manager = new MenuManager("Order by");
662         manager.add(sortByTimeAction);
663         manager.add(sortBySeverityAction);
664         manager.add(sortByMessageAction);
665         return manager;
666     }
667
668     class SortAction extends Action {
669
670         private final int sortBy;
671
672         public SortAction(String text, int sortBy) {
673             super(text, IAction.AS_RADIO_BUTTON);
674             this.sortBy = sortBy;
675
676             if (sortCandidate == sortBy) {
677                 setChecked(true);
678             }
679         }
680
681         @Override
682         public void run() {
683             sortBySeverityAction.setChecked(false);
684             sortByTimeAction.setChecked(false);
685             sortCandidate = sortBy;
686             setChecked(true);
687
688             ViewerComparator comparator;
689             TreeColumn column;
690             if (sortBy == ORDER_BY_SEVERITY) {
691                 comparator = severityComparator;
692                 column = severityColumn;
693             } else if (sortBy == ORDER_BY_TIME) {
694                 comparator = dateComparator;
695                 column = dateColumn;
696             } else { // Order by message
697                 comparator = messageComparator;
698                 column = messageColumn;
699             }
700             TreeViewer viewer = tree.getViewer();
701             viewer.setComparator(comparator);
702             viewer.getTree().setSortColumn(column);
703             if (column.equals(sortColumn)) { // reverse sorting order
704                 sortDirection = viewer.getTree().getSortDirection() == SWT.UP ? DOWN
705                         : UP;
706                 viewer.getTree().setSortDirection(
707                         sortDirection == UP ? SWT.UP : SWT.DOWN);
708                 viewer.refresh();
709             } else { // set this column as the one to sort by
710                 sortDirection = DOWN;
711                 viewer.getTree().setSortDirection(SWT.DOWN);
712             }
713             sortColumn = column;
714             refresh();
715         }
716     }
717
718     private void refresh() {
719         tree.getViewer().refresh();
720     }
721
722     @Override
723     public void setFocus() {
724         tree.setFocus();
725     }
726
727     @Override
728     public void dispose() {
729         logManager.removeLogListener(logListener);
730         super.dispose();
731     }
732 }