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 java.io.BufferedWriter;
20 import java.io.FileWriter;
21 import java.io.IOException;
22 import java.text.DateFormat;
23 import java.text.SimpleDateFormat;
24 import java.util.Date;
25 import java.util.HashMap;
26 import java.util.List;
28 import oic.simulator.clientcontroller.Activator;
29 import oic.simulator.clientcontroller.listener.ILogUIListener;
30 import oic.simulator.clientcontroller.manager.LogManager;
31 import oic.simulator.clientcontroller.utils.Constants;
32 import oic.simulator.clientcontroller.view.dialogs.FilterDialog;
33 import oic.simulator.clientcontroller.view.dialogs.LogDetailsDialog;
34 import oic.simulator.logger.LogContentProvider;
35 import oic.simulator.logger.LogEntry;
36 import oic.simulator.logger.LogLabelProvider;
38 import org.eclipse.jface.action.Action;
39 import org.eclipse.jface.action.IAction;
40 import org.eclipse.jface.action.IContributionItem;
41 import org.eclipse.jface.action.IMenuManager;
42 import org.eclipse.jface.action.IToolBarManager;
43 import org.eclipse.jface.action.MenuManager;
44 import org.eclipse.jface.action.Separator;
45 import org.eclipse.jface.dialogs.MessageDialog;
46 import org.eclipse.jface.resource.ImageDescriptor;
47 import org.eclipse.jface.viewers.DoubleClickEvent;
48 import org.eclipse.jface.viewers.IDoubleClickListener;
49 import org.eclipse.jface.viewers.ISelectionChangedListener;
50 import org.eclipse.jface.viewers.IStructuredSelection;
51 import org.eclipse.jface.viewers.SelectionChangedEvent;
52 import org.eclipse.jface.viewers.StructuredSelection;
53 import org.eclipse.jface.viewers.TreeViewer;
54 import org.eclipse.jface.viewers.Viewer;
55 import org.eclipse.jface.viewers.ViewerComparator;
56 import org.eclipse.jface.window.Window;
57 import org.eclipse.swt.SWT;
58 import org.eclipse.swt.events.KeyEvent;
59 import org.eclipse.swt.events.KeyListener;
60 import org.eclipse.swt.events.SelectionAdapter;
61 import org.eclipse.swt.events.SelectionEvent;
62 import org.eclipse.swt.layout.GridData;
63 import org.eclipse.swt.widgets.Composite;
64 import org.eclipse.swt.widgets.Display;
65 import org.eclipse.swt.widgets.FileDialog;
66 import org.eclipse.swt.widgets.Text;
67 import org.eclipse.swt.widgets.Tree;
68 import org.eclipse.swt.widgets.TreeColumn;
69 import org.eclipse.swt.widgets.TreeItem;
70 import org.eclipse.ui.IActionBars;
71 import org.eclipse.ui.IWorkbenchActionConstants;
72 import org.eclipse.ui.IWorkbenchPage;
73 import org.eclipse.ui.dialogs.FilteredTree;
74 import org.eclipse.ui.dialogs.PatternFilter;
75 import org.eclipse.ui.part.ViewPart;
76 import org.oic.simulator.ILogger.Level;
79 * This class manages and shows the log view in the perspective.
81 public class LogView extends ViewPart {
83 public static final String VIEW_ID = "oic.simulator.clientcontroller.view.log";
85 private LogManager logManager;
86 private ILogUIListener logListener;
88 private LogContentProvider treeContentProvider;
90 private FilteredTree tree;
91 private TreeColumn severityColumn;
92 private TreeColumn dateColumn;
93 private TreeColumn messageColumn;
95 private IAction exportLogAction;
96 private IAction clearLogAction;
97 private IAction deleteLogAction;
98 private IAction scrollLockAction;
99 private IAction logDetailsAction;
100 private IAction filterAction;
101 private IAction activateViewAction;
102 private IAction showTextFilter;
103 private IContributionItem groupByAction;
105 private HashMap<Integer, Boolean> shownSeverities = new HashMap<Integer, Boolean>();
107 private boolean activateOnChange = false;
109 private boolean hideTextFilter = false;
111 private boolean scrollLockDisabled;
113 public static final int ORDER_BY_TIME = 0;
114 public static final int ORDER_BY_SEVERITY = 1;
115 public static final int ORDER_BY_MESSAGE = 2;
117 int sortCandidate = ORDER_BY_TIME;
119 SortAction sortByTimeAction = new SortAction(
122 SortAction sortBySeverityAction = new SortAction(
125 SortAction sortByMessageAction = new SortAction(
129 private ViewerComparator dateComparator;
130 private ViewerComparator severityComparator;
131 private ViewerComparator messageComparator;
133 private TreeColumn sortColumn = null;
134 private static int DOWN = 1;
135 private static int UP = -1;
136 private int sortDirection = DOWN;
140 logListener = new ILogUIListener() {
143 public void logChanged(final List<LogEntry> entry) {
144 Display.getDefault().asyncExec(new Runnable() {
148 TreeViewer viewer = tree.getViewer();
149 if (viewer.getControl().isDisposed()) {
152 viewer.setInput(entry);
159 public void logAdded(final LogEntry added) {
160 Display.getDefault().asyncExec(new Runnable() {
164 TreeViewer viewer = tree.getViewer();
165 if (viewer.getControl().isDisposed()) {
168 LogContentProvider provider = (LogContentProvider) viewer
169 .getContentProvider();
170 provider.addLog(added);
171 tree.getViewer().add(viewer.getInput(), added);
172 @SuppressWarnings("unchecked")
173 List<LogEntry> input = (List<LogEntry>) viewer
175 if (input.size() > Constants.LOG_SIZE) {
176 viewer.remove(viewer.getInput(), 0);
183 private void updateTree(boolean needscroll) {
184 if (activateOnChange) {
185 IWorkbenchPage page = Activator.getDefault().getWorkbench()
186 .getActiveWorkbenchWindow().getActivePage();
188 page.bringToTop(LogView.this);
191 if (scrollLockDisabled && needscroll) {
192 Tree tree2 = tree.getViewer().getTree();
193 if (tree2.getItemCount() > 0) {
194 TreeItem item = tree2.getItem(tree2.getItemCount() - 1);
195 tree2.setTopItem(item);
196 deleteLogAction.setEnabled(true);
202 logManager = Activator.getDefault().getLogManager();
204 // Initially state of scroll lock
205 scrollLockDisabled = true;
209 public void createPartControl(Composite parent) {
210 PatternFilter filter = new PatternFilter() {
212 DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
215 protected boolean isLeafMatch(Viewer viewer, Object element) {
216 if (element instanceof LogEntry) {
217 LogEntry logEntry = (LogEntry) element;
218 String severity = LogManager.getSeverityName(logEntry
220 String date = dateFormat.format(logEntry.getDate());
221 String message = logEntry.getMessage();
222 return wordMatches(severity) || wordMatches(date)
223 || wordMatches(message);
228 filter.setIncludeLeadingWildcard(true);
229 tree = new FilteredTree(parent, SWT.SINGLE | SWT.H_SCROLL
230 | SWT.V_SCROLL | SWT.FULL_SELECTION, filter, true);
234 createColumnComparators();
238 setDefaultShownSeverities();
240 IActionBars actionBars = getViewSite().getActionBars();
241 IToolBarManager toolBarManager = actionBars.getToolBarManager();
242 toolBarManager.add(exportLogAction);
243 toolBarManager.add(clearLogAction);
244 toolBarManager.add(deleteLogAction);
245 toolBarManager.add(scrollLockAction);
247 .add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
249 IMenuManager mgr = actionBars.getMenuManager();
250 mgr.add(groupByAction);
251 mgr.add(new Separator());
252 mgr.add(filterAction);
253 mgr.add(new Separator());
254 mgr.add(activateViewAction);
255 mgr.add(showTextFilter);
257 addManagerListeners();
259 if (sortCandidate == ORDER_BY_TIME) {
260 sortByTimeAction.run();
261 } else if (sortCandidate == ORDER_BY_SEVERITY) {
262 sortBySeverityAction.run();
263 } else { // order_selected == ORDER_BY_NONE
264 sortByMessageAction.run();
269 private void setupFilteredTree() {
270 tree.setLayoutData(new GridData(GridData.FILL_BOTH));
271 final Tree innerTree = tree.getViewer().getTree();
272 innerTree.setLinesVisible(true);
274 severityColumn = new TreeColumn(innerTree, SWT.LEFT);
275 severityColumn.setText("Severity");
276 severityColumn.setWidth(110);
277 severityColumn.addSelectionListener(new SelectionAdapter() {
280 public void widgetSelected(SelectionEvent e) {
281 sortBySeverityAction.run();
284 dateColumn = new TreeColumn(innerTree, SWT.LEFT);
285 dateColumn.setText("Time");
286 dateColumn.setWidth(110);
287 dateColumn.addSelectionListener(new SelectionAdapter() {
290 public void widgetSelected(SelectionEvent e) {
291 sortByTimeAction.run();
294 messageColumn = new TreeColumn(innerTree, SWT.LEFT);
295 messageColumn.setText("Message");
296 messageColumn.setWidth(180);
297 messageColumn.addSelectionListener(new SelectionAdapter() {
299 public void widgetSelected(SelectionEvent e) {
300 sortByMessageAction.run();
304 innerTree.setHeaderVisible(true);
306 treeContentProvider = new LogContentProvider();
308 tree.getViewer().setContentProvider(treeContentProvider);
309 tree.getViewer().setLabelProvider(new LogLabelProvider());
311 tree.getViewer().setInput(logManager.getLogEntries());
313 tree.getViewer().addSelectionChangedListener(
314 new ISelectionChangedListener() {
317 public void selectionChanged(SelectionChangedEvent event) {
318 deleteLogAction.setEnabled(!tree.getViewer()
319 .getSelection().isEmpty());
320 logDetailsAction.setEnabled(!tree.getViewer()
321 .getSelection().isEmpty());
325 tree.getViewer().getTree().addKeyListener(new KeyListener() {
328 public void keyReleased(KeyEvent e) {
332 public void keyPressed(KeyEvent e) {
333 if (e.character == (char) 127) { // If delete key is pressed
334 if (deleteLogAction.isEnabled()) {
335 deleteLogAction.run();
341 tree.getViewer().addDoubleClickListener(new IDoubleClickListener() {
344 public void doubleClick(DoubleClickEvent event) {
345 logDetailsAction.run();
350 private void createColumnComparators() {
351 dateComparator = new ViewerComparator() {
354 public int compare(Viewer viewer, Object e1, Object e2) {
355 LogEntry l1 = (LogEntry) e1;
356 LogEntry l2 = (LogEntry) e2;
357 return l1.getDate().compareTo(l2.getDate()) * sortDirection;
361 severityComparator = new ViewerComparator() {
364 public int compare(Viewer viewer, Object e1, Object e2) {
365 LogEntry l1 = (LogEntry) e1;
366 LogEntry l2 = (LogEntry) e2;
367 if (l1.getSeverity() < l2.getSeverity()) {
368 return -1 * sortDirection;
370 if (l1.getSeverity() > l2.getSeverity()) {
371 return 1 * sortDirection;
377 messageComparator = new ViewerComparator() {
380 public int compare(Viewer viewer, Object e1, Object e2) {
381 LogEntry l1 = (LogEntry) e1;
382 LogEntry l2 = (LogEntry) e2;
383 return l1.getMessage().compareTo(l2.getMessage())
390 private void setDefaultShownSeverities() {
391 shownSeverities.put(Level.INFO.ordinal(), true);
392 shownSeverities.put(Level.DEBUG.ordinal(), true);
393 shownSeverities.put(Level.WARNING.ordinal(), true);
394 shownSeverities.put(Level.ERROR.ordinal(), true);
397 private void addManagerListeners() {
398 logManager.addLogListener(logListener);
399 logManager.applyFilter(shownSeverities);
402 private void createActions() {
403 exportLogAction = createExportLogAction();
404 clearLogAction = createClearLogAction();
405 deleteLogAction = createDeleteLogAction();
406 scrollLockAction = createScrollLockAction();
407 logDetailsAction = createLogDetailsAction();
409 filterAction = createFilterAction();
410 activateViewAction = createActivateViewAction();
411 showTextFilter = createShowTextFilter();
412 groupByAction = createGroupByAction();
415 private IAction createExportLogAction() {
416 Action action = new Action("Export log") {
419 FileDialog fd = new FileDialog(Display.getDefault()
420 .getActiveShell(), SWT.SAVE);
421 fd.setOverwrite(true);
422 fd.setFileName("OIC_Simulator_ServerLog.log");
423 fd.setFilterExtensions(Constants.SAVE_LOG_FILTER_EXTENSIONS);
424 String name = fd.open();
425 List<LogEntry> logEntries = logManager.getLogEntries();
426 StringBuilder sb = new StringBuilder();
427 for (LogEntry entry : logEntries) {
428 sb.append(entry.toString());
430 String data = sb.toString();
431 BufferedWriter out = null;
433 out = new BufferedWriter(new FileWriter(name));
435 } catch (IOException e) {
437 MessageDialog.openError(
438 Display.getDefault().getActiveShell(),
440 "Could not export log. IO exception: "
447 } catch (IOException e) {
451 .log(Level.ERROR.ordinal(),
453 "[" + e.getClass().getSimpleName()
454 + "]" + e.getMessage());
459 action.setToolTipText("Export log");
461 action.setImageDescriptor(ImageDescriptor.createFromFile(
462 this.getClass(), "/icons/export_log_e.gif"));
463 action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
464 this.getClass(), "/icons/export_log_d.gif"));
465 action.setEnabled(true);
470 private IAction createClearLogAction() {
471 Action action = new Action("Clear log") {
475 logManager.clearLog();
478 action.setToolTipText("Clear log");
480 action.setImageDescriptor(ImageDescriptor.createFromFile(
481 this.getClass(), "/icons/clear_e.gif"));
482 action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
483 this.getClass(), "/icons/clear_d.gif"));
484 action.setEnabled(true);
488 private IAction createDeleteLogAction() {
489 Action action = new Action("Delete log entry") {
492 @SuppressWarnings("unchecked")
494 IStructuredSelection selection = (IStructuredSelection) tree
495 .getViewer().getSelection();
496 List<LogEntry> entries = (List<LogEntry>) tree.getViewer()
498 LogEntry selectedEntry = (LogEntry) selection.getFirstElement();
499 if (null != selectedEntry) {
500 LogEntry toBeShownEntry = null;
501 for (LogEntry entry : entries) {
502 if (entry.equals(selectedEntry)) {
503 int size = entries.size();
504 int index = entries.indexOf(selectedEntry);
505 if (index + 1 < size) {
506 toBeShownEntry = entries.get(index + 1);
507 } else if (index > 0) {
508 toBeShownEntry = entries.get(index - 1);
513 logManager.removeEntry(selectedEntry);
514 if (null != toBeShownEntry) {
515 tree.getViewer().setSelection(
516 new StructuredSelection(toBeShownEntry));
521 action.setToolTipText("Delete log entry");
522 action.setImageDescriptor(ImageDescriptor.createFromFile(
523 this.getClass(), "/icons/delete_e.gif"));
524 action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
525 this.getClass(), "/icons/delete_d.gif"));
526 action.setEnabled(false);
530 private IAction createScrollLockAction() {
531 Action action = new Action("Scroll lock") {
535 scrollLockDisabled = !this.isChecked();
539 public int getStyle() {
540 return IAction.AS_CHECK_BOX;
543 action.setToolTipText("Scroll lock");
544 action.setImageDescriptor(ImageDescriptor.createFromFile(
545 this.getClass(), "/icons/lock_e.gif"));
546 action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
547 this.getClass(), "/icons/lock_d.gif"));
548 action.setEnabled(true);
552 private IAction createLogDetailsAction() {
553 Action action = new Action("Details...") {
557 Display.getDefault().asyncExec(new Runnable() {
561 LogEntry x = (LogEntry) ((IStructuredSelection) tree
562 .getViewer().getSelection()).getFirstElement();
564 new LogDetailsDialog(Display.getDefault()
565 .getActiveShell(), LogManager.getSeverityName(x
566 .getSeverity()), LogManager.getSeverityIcon(x
567 .getSeverity()), x.getDate(), x.getMessage())
573 action.setToolTipText("Details...");
574 action.setImageDescriptor(ImageDescriptor.createFromFile(
575 this.getClass(), "/icons/log_details_e.gif"));
576 action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
577 this.getClass(), "/icons/log_details_e.gif"));
578 action.setEnabled(false);
582 private IAction createFilterAction() {
583 Action action = new Action("Filters ...") {
587 FilterDialog fd = new FilterDialog(Display.getDefault()
588 .getActiveShell(), shownSeverities);
589 if (fd.open() == Window.OK) {
590 logManager.applyFilter(shownSeverities);
592 tree.getViewer().refresh();
595 action.setToolTipText("Filters ...");
597 action.setImageDescriptor(ImageDescriptor.createFromFile(
598 this.getClass(), "/icons/filter_e.gif"));
599 action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
600 this.getClass(), "/icons/filter_d.gif"));
601 action.setEnabled(true);
605 private IAction createActivateViewAction() {
606 Action action = new Action("Activate view on new events",
607 IAction.AS_CHECK_BOX) {
611 activateOnChange = this.isChecked();
614 action.setChecked(activateOnChange);
615 action.setToolTipText("Activate view on new events");
617 action.setImageDescriptor(ImageDescriptor.createFromFile(
618 this.getClass(), "/icons/prop_e.gif"));
619 action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
620 this.getClass(), "/icons/prop_d.gif"));
621 action.setEnabled(true);
625 private IAction createShowTextFilter() {
626 Action action = new Action("Show text filter", IAction.AS_CHECK_BOX) {
630 Text filterControl = tree.getFilterControl();
631 Composite filterComposite = filterControl.getParent();
632 GridData gd = (GridData) filterComposite.getLayoutData();
633 boolean visible = isChecked();
634 gd.exclude = !visible;
635 filterComposite.setVisible(visible);
636 filterControl.setText("");
638 filterControl.selectAll();
642 hideTextFilter = !visible;
645 action.setToolTipText("Show text filter");
647 action.setImageDescriptor(ImageDescriptor.createFromFile(
648 this.getClass(), "/icons/tree_mode_e.gif"));
649 action.setDisabledImageDescriptor(ImageDescriptor.createFromFile(
650 this.getClass(), "/icons/tree_mode_d.gif"));
651 action.setEnabled(true);
652 action.setChecked(!hideTextFilter);
653 if (hideTextFilter) {
659 private IContributionItem createGroupByAction() {
660 IMenuManager manager = new MenuManager("Order by");
661 manager.add(sortByTimeAction);
662 manager.add(sortBySeverityAction);
663 manager.add(sortByMessageAction);
667 class SortAction extends Action {
669 private final int sortBy;
671 public SortAction(String text, int sortBy) {
672 super(text, IAction.AS_RADIO_BUTTON);
673 this.sortBy = sortBy;
675 if (sortCandidate == sortBy) {
682 sortBySeverityAction.setChecked(false);
683 sortByTimeAction.setChecked(false);
684 sortCandidate = sortBy;
687 ViewerComparator comparator;
689 if (sortBy == ORDER_BY_SEVERITY) {
690 comparator = severityComparator;
691 column = severityColumn;
692 } else if (sortBy == ORDER_BY_TIME) {
693 comparator = dateComparator;
695 } else { // Order by message
696 comparator = messageComparator;
697 column = messageColumn;
699 TreeViewer viewer = tree.getViewer();
700 viewer.setComparator(comparator);
701 viewer.getTree().setSortColumn(column);
702 if (column.equals(sortColumn)) { // reverse sorting order
703 sortDirection = viewer.getTree().getSortDirection() == SWT.UP ? DOWN
705 viewer.getTree().setSortDirection(
706 sortDirection == UP ? SWT.UP : SWT.DOWN);
708 } else { // set this column as the one to sort by
709 sortDirection = DOWN;
710 viewer.getTree().setSortDirection(SWT.DOWN);
717 private void refresh() {
718 tree.getViewer().refresh();
722 public void setFocus() {
727 public void dispose() {
728 logManager.removeLogListener(logListener);