2 * Copyright 2015 Samsung Electronics All Rights Reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package oic.simulator.clientcontroller.view;
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;
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;
68 import org.oic.simulator.ILogger.Level;
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;
81 * This class manages and shows the log view in the perspective.
83 public class LogView extends ViewPart {
85 public static final String VIEW_ID = "oic.simulator.clientcontroller.view.log";
87 private LogManager logManager;
88 private ILogUIListener logListener;
90 private LogContentProvider treeContentProvider;
92 private FilteredTree tree;
93 private TreeColumn severityColumn;
94 private TreeColumn dateColumn;
95 private TreeColumn messageColumn;
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;
107 private HashMap<Integer, Boolean> shownSeverities = new HashMap<Integer, Boolean>();
109 private boolean activateOnChange = false;
111 private boolean hideTextFilter = false;
113 private boolean scrollLockDisabled;
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;
119 int sortCandidate = ORDER_BY_TIME;
121 SortAction sortByTimeAction = new SortAction(
124 SortAction sortBySeverityAction = new SortAction(
127 SortAction sortByMessageAction = new SortAction(
131 private ViewerComparator dateComparator;
132 private ViewerComparator severityComparator;
133 private ViewerComparator messageComparator;
135 private TreeColumn sortColumn = null;
136 private static int DOWN = 1;
137 private static int UP = -1;
138 private int sortDirection = DOWN;
142 logListener = new ILogUIListener() {
145 public void logChanged(final List<LogEntry> entry) {
146 Display.getDefault().asyncExec(new Runnable() {
150 TreeViewer viewer = tree.getViewer();
151 if (viewer.getControl().isDisposed()) {
154 viewer.setInput(entry);
161 public void logAdded(final LogEntry added) {
162 Display.getDefault().asyncExec(new Runnable() {
166 TreeViewer viewer = tree.getViewer();
167 if (viewer.getControl().isDisposed()) {
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
177 if (input.size() > Constants.LOG_SIZE) {
178 viewer.remove(viewer.getInput(), 0);
185 private void updateTree(boolean needscroll) {
186 if (activateOnChange) {
187 IWorkbenchPage page = Activator.getDefault().getWorkbench()
188 .getActiveWorkbenchWindow().getActivePage();
190 page.bringToTop(LogView.this);
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);
204 logManager = Activator.getDefault().getLogManager();
206 // Initially state of scroll lock
207 scrollLockDisabled = true;
211 public void createPartControl(Composite parent) {
212 PatternFilter filter = new PatternFilter() {
214 DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
217 protected boolean isLeafMatch(Viewer viewer, Object element) {
218 if (element instanceof LogEntry) {
219 LogEntry logEntry = (LogEntry) element;
220 String severity = LogManager.getSeverityName(logEntry
222 String date = dateFormat.format(logEntry.getDate());
223 String message = logEntry.getMessage();
224 return wordMatches(severity) || wordMatches(date)
225 || wordMatches(message);
230 filter.setIncludeLeadingWildcard(true);
231 tree = new FilteredTree(parent, SWT.SINGLE | SWT.H_SCROLL
232 | SWT.V_SCROLL | SWT.FULL_SELECTION, filter, true);
236 createColumnComparators();
240 setDefaultShownSeverities();
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);
249 .add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
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);
259 addManagerListeners();
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();
271 private void setupFilteredTree() {
272 tree.setLayoutData(new GridData(GridData.FILL_BOTH));
273 final Tree innerTree = tree.getViewer().getTree();
274 innerTree.setLinesVisible(true);
276 severityColumn = new TreeColumn(innerTree, SWT.LEFT);
277 severityColumn.setText("Severity");
278 severityColumn.setWidth(110);
279 severityColumn.addSelectionListener(new SelectionAdapter() {
282 public void widgetSelected(SelectionEvent e) {
283 sortBySeverityAction.run();
286 dateColumn = new TreeColumn(innerTree, SWT.LEFT);
287 dateColumn.setText("Time");
288 dateColumn.setWidth(110);
289 dateColumn.addSelectionListener(new SelectionAdapter() {
292 public void widgetSelected(SelectionEvent e) {
293 sortByTimeAction.run();
296 messageColumn = new TreeColumn(innerTree, SWT.LEFT);
297 messageColumn.setText("Message");
298 messageColumn.setWidth(180);
299 messageColumn.addSelectionListener(new SelectionAdapter() {
301 public void widgetSelected(SelectionEvent e) {
302 sortByMessageAction.run();
306 innerTree.setHeaderVisible(true);
308 treeContentProvider = new LogContentProvider();
310 tree.getViewer().setContentProvider(treeContentProvider);
311 tree.getViewer().setLabelProvider(new LogLabelProvider());
313 tree.getViewer().setInput(logManager.getLogEntries());
315 tree.getViewer().addSelectionChangedListener(
316 new ISelectionChangedListener() {
319 public void selectionChanged(SelectionChangedEvent event) {
320 deleteLogAction.setEnabled(!tree.getViewer()
321 .getSelection().isEmpty());
322 logDetailsAction.setEnabled(!tree.getViewer()
323 .getSelection().isEmpty());
327 tree.getViewer().getTree().addKeyListener(new KeyListener() {
330 public void keyReleased(KeyEvent e) {
334 public void keyPressed(KeyEvent e) {
335 if (e.character == (char) 127) { // If delete key is pressed
336 if (deleteLogAction.isEnabled()) {
337 deleteLogAction.run();
343 tree.getViewer().addDoubleClickListener(new IDoubleClickListener() {
346 public void doubleClick(DoubleClickEvent event) {
347 logDetailsAction.run();
352 private void createColumnComparators() {
353 dateComparator = new ViewerComparator() {
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;
363 severityComparator = new ViewerComparator() {
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;
372 if (l1.getSeverity() > l2.getSeverity()) {
373 return 1 * sortDirection;
379 messageComparator = new ViewerComparator() {
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())
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);
399 private void addManagerListeners() {
400 logManager.addLogListener(logListener);
401 logManager.applyFilter(shownSeverities);
404 private void createActions() {
405 exportLogAction = createExportLogAction();
406 clearLogAction = createClearLogAction();
407 deleteLogAction = createDeleteLogAction();
408 scrollLockAction = createScrollLockAction();
409 logDetailsAction = createLogDetailsAction();
411 filterAction = createFilterAction();
412 activateViewAction = createActivateViewAction();
413 showTextFilter = createShowTextFilter();
414 groupByAction = createGroupByAction();
417 private IAction createExportLogAction() {
418 Action action = new Action("Export log") {
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());
432 String data = sb.toString();
433 BufferedWriter out = null;
435 out = new BufferedWriter(new OutputStreamWriter(
436 new FileOutputStream(name), "UTF-8"));
438 } catch (Exception e) {
440 MessageDialog.openError(
441 Display.getDefault().getActiveShell(),
443 "Could not export log. IO exception: "
450 } catch (IOException e) {
454 .log(Level.ERROR.ordinal(),
456 "[" + e.getClass().getSimpleName()
457 + "]" + e.getMessage());
462 action.setToolTipText("Export log");
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);
473 private IAction createClearLogAction() {
474 Action action = new Action("Clear log") {
478 logManager.clearLog();
481 action.setToolTipText("Clear log");
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);
491 private IAction createDeleteLogAction() {
492 Action action = new Action("Delete log entry") {
495 @SuppressWarnings("unchecked")
497 IStructuredSelection selection = (IStructuredSelection) tree
498 .getViewer().getSelection();
499 List<LogEntry> entries = (List<LogEntry>) tree.getViewer()
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);
516 logManager.removeEntry(selectedEntry);
517 if (null != toBeShownEntry) {
518 tree.getViewer().setSelection(
519 new StructuredSelection(toBeShownEntry));
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);
533 private IAction createScrollLockAction() {
534 Action action = new Action("Scroll lock") {
538 scrollLockDisabled = !this.isChecked();
542 public int getStyle() {
543 return IAction.AS_CHECK_BOX;
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);
555 private IAction createLogDetailsAction() {
556 Action action = new Action("Details...") {
560 Display.getDefault().asyncExec(new Runnable() {
564 LogEntry x = (LogEntry) ((IStructuredSelection) tree
565 .getViewer().getSelection()).getFirstElement();
567 new LogDetailsDialog(Display.getDefault()
568 .getActiveShell(), LogManager.getSeverityName(x
569 .getSeverity()), LogManager.getSeverityIcon(x
570 .getSeverity()), x.getDate(), x.getMessage())
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);
585 private IAction createFilterAction() {
586 Action action = new Action("Filters ...") {
590 FilterDialog fd = new FilterDialog(Display.getDefault()
591 .getActiveShell(), shownSeverities);
592 if (fd.open() == Window.OK) {
593 logManager.applyFilter(shownSeverities);
595 tree.getViewer().refresh();
598 action.setToolTipText("Filters ...");
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);
608 private IAction createActivateViewAction() {
609 Action action = new Action("Activate view on new events",
610 IAction.AS_CHECK_BOX) {
614 activateOnChange = this.isChecked();
617 action.setChecked(activateOnChange);
618 action.setToolTipText("Activate view on new events");
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);
628 private IAction createShowTextFilter() {
629 Action action = new Action("Show text filter", IAction.AS_CHECK_BOX) {
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("");
641 filterControl.selectAll();
645 hideTextFilter = !visible;
648 action.setToolTipText("Show text filter");
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) {
662 private IContributionItem createGroupByAction() {
663 IMenuManager manager = new MenuManager("Order by");
664 manager.add(sortByTimeAction);
665 manager.add(sortBySeverityAction);
666 manager.add(sortByMessageAction);
670 class SortAction extends Action {
672 private final int sortBy;
674 public SortAction(String text, int sortBy) {
675 super(text, IAction.AS_RADIO_BUTTON);
676 this.sortBy = sortBy;
678 if (sortCandidate == sortBy) {
685 sortBySeverityAction.setChecked(false);
686 sortByTimeAction.setChecked(false);
687 sortCandidate = sortBy;
690 ViewerComparator comparator;
692 if (sortBy == ORDER_BY_SEVERITY) {
693 comparator = severityComparator;
694 column = severityColumn;
695 } else if (sortBy == ORDER_BY_TIME) {
696 comparator = dateComparator;
698 } else { // Order by message
699 comparator = messageComparator;
700 column = messageColumn;
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
708 viewer.getTree().setSortDirection(
709 sortDirection == UP ? SWT.UP : SWT.DOWN);
711 } else { // set this column as the one to sort by
712 sortDirection = DOWN;
713 viewer.getTree().setSortDirection(SWT.DOWN);
720 private void refresh() {
721 tree.getViewer().refresh();
725 public void setFocus() {
730 public void dispose() {
731 logManager.removeLogListener(logListener);