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