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