Java tutorial
/* * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * This component and the accompanying materials are made available * under the terms of "Eclipse Public License v1.0" * which accompanies this distribution, and is available * at the URL "http://www.eclipse.org/legal/epl-v10.html". * * Initial Contributors: * Nokia Corporation - initial contribution. * * Contributors: * * Description: * */ package com.nokia.s60tools.memspy.ui.dialogs; import java.util.ArrayList; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.dialogs.TitleAreaDialog; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PlatformUI; import com.nokia.s60tools.memspy.model.SWMTCategoryConstants; import com.nokia.s60tools.memspy.model.SWMTCategorys; import com.nokia.s60tools.memspy.preferences.MemSpyPreferences; import com.nokia.s60tools.memspy.resources.HelpContextIDs; import com.nokia.s60tools.memspy.resources.ImageKeys; import com.nokia.s60tools.memspy.resources.ImageResourceManager; import com.nokia.s60tools.memspy.util.MemSpyConsole; import com.nokia.s60tools.ui.S60ToolsTable; import com.nokia.s60tools.ui.S60ToolsTableColumnData; import com.nokia.s60tools.ui.S60ToolsTableFactory; import com.nokia.s60tools.ui.S60ToolsUIConstants; /** * Dialog for selecting SWMT categories to be tracked. */ public class SWMTCategoriesDialog extends TitleAreaDialog { // // Private classes // private static final String HEAP_DATA_THREAD_FILTER_TXT = "Heap Data Thread Filter"; /** * Label provider for table viewer component. */ class SWMTCategoryViewerLabelProvider extends LabelProvider implements ITableLabelProvider { /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) */ public Image getColumnImage(Object element, int columnIndex) { return null; // No images used } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) */ public String getColumnText(Object element, int columnIndex) { String label = element.toString(); SWMTCategoryEntry entryData = (SWMTCategoryEntry) element; switch (columnIndex) { case SWMTCategoryEntry.NAME_COLUMN_INDEX: label = entryData.getCategoryName(); break; default: MemSpyConsole.getInstance().println("Unexpected column index: " + columnIndex, //$NON-NLS-1$ MemSpyConsole.MSG_ERROR); //$NON-NLS-2$ break; } return label; } } // // Private constants // /** * Columns in the container area. */ private static final int COLUMN_COUNT = 1; /** * Dialog width. */ private static final int DIALOG_WIDTH = 425; /** * Dialog height. */ private static final int DIALOG_HEIGHT = 550; /** * Percentage as decimal number how much table viewer is taking space horizontally. */ private static final double TABLE_VIEWER_WIDTH_PERCENTAGE = 0.8; /** * Default guiding message shown to the user in add new mode. */ private static final String DEFAULT_MESSAGE = "Set advanced options and tracked SWMT categories."; /** * Complete message shown to the user in add new mode. */ private static final String COMPLETE_MESSAGE = "Press OK to save advanced options and set categories to be tracked"; /** * Error message shown to the user in case no categories are selected. */ private static final String ERROR_MESSAGE = "At least single category must be selected"; /** * UI text for closing Symbian agent */ private static final String CLOSE_MEM_SPY_BETWEEN_CYCLES_TEXT = "Close MemSpy Symbian Agent Between Cycles"; /** * Tip text for closing Symbian agent */ private static final String CLOSE_MEM_SPY_BETWEEN_CYCLES_TIP_TEXT = "Choose if the MemSpy Symbian agent in S60 target is closed between cycles. That is more realistic use case for memory usage point of view."; // // Member data // /** * Flag used to make sure that create() and open() are called in correct order. */ private boolean isCreateCalled = false; // // UI Controls // /** * Container area for individual fields for the user for entering information. */ private Composite container; /** * Reference to OK button that can be disabled/enabled * due to current category selection- */ private Button okActionBtn; /** * Viewer showing currently selected category file entries. */ private CheckboxTableViewer categoryViewer; /** * Selected categories as a result of bitwise OR. */ private int categorySelection = SWMTCategoryConstants.CATEGORY_ALL; //User Heap filter text field private Text heapText; private Button closeBetweenCyclesButton; private Button heapDumpBtn; /** * Constructor. Used to open dialog in order to add new entry. * @param parentShell Parent shell for the dialog. * @param categorySelection integer containing initially selected categories as a result of bitwise OR. */ public SWMTCategoriesDialog(Shell parentShell, int categorySelection) { super(parentShell); this.categorySelection = categorySelection; // Setting banner image String bannerImage = ImageKeys.IMG_WIZARD; setTitleImage(ImageResourceManager.getImage(bannerImage)); } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) */ protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, true); okActionBtn = getButton(IDialogConstants.OK_ID); } /* (non-Javadoc) * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) */ protected void configureShell(Shell shell) { super.configureShell(shell); shell.setText("SWMT Categories and Advanced Options"); } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) */ protected Control createDialogArea(Composite parent) { Composite dialogAreaComposite = (Composite) super.createDialogArea(parent); // // Creating container and layout for it // container = new Composite(dialogAreaComposite, SWT.NONE); GridLayout gdl = new GridLayout(COLUMN_COUNT, false); // Settings margins according Carbide branding guideline gdl.marginLeft = S60ToolsUIConstants.MARGIN_BTW_FRAME_AND_CONTENTS; gdl.marginRight = S60ToolsUIConstants.MARGIN_BTW_FRAME_AND_CONTENTS; gdl.marginTop = S60ToolsUIConstants.MARGIN_BTW_FRAME_AND_CONTENTS; gdl.marginBottom = S60ToolsUIConstants.MARGIN_BTW_FRAME_AND_CONTENTS; container.setLayout(gdl); container.setLayoutData(new GridData(GridData.FILL_BOTH)); // // Symbian agent options group // createSymbianAgentOptionsGroup(); // // Head dump group // createHeapDumpGroup(); // // Creating table viewer for showing category file entries // categoryViewer = createCategoryCheckBoxTableViewer(container); GridData categoryViewerGd = new GridData(GridData.FILL_BOTH); // Spanning as many rows as there are actions buttons on the right categoryViewerGd.verticalSpan = 3; categoryViewerGd.widthHint = (int) (TABLE_VIEWER_WIDTH_PERCENTAGE * DIALOG_WIDTH); categoryViewer.getControl().setLayoutData(categoryViewerGd); categoryViewer.setSorter(new SWMTCategoryEntryTableViewerSorter()); // Adding selection change listener categoryViewer.addSelectionChangedListener(new ISelectionChangedListener() { /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) */ public void selectionChanged(SelectionChangedEvent event) { notifySelectionChanged(); } }); // // Setting providers for table viewer // // Creating content provider GategoryProvider categoryViewerContentProvider = new GategoryProvider(); // Setting content provider categoryViewer.setContentProvider(categoryViewerContentProvider); categoryViewer.setInput(categoryViewerContentProvider); // Label provider categoryViewer.setLabelProvider(new SWMTCategoryViewerLabelProvider()); // Setting initial category selection state InitializeSelectionState(); // Setting context-sensitive help ID PlatformUI.getWorkbench().getHelpSystem().setHelp(dialogAreaComposite, HelpContextIDs.MEMSPY_IMPORT_SWMT_CATEGORIES_DIALOG); // Dialog are composite ready return dialogAreaComposite; } /** * Private class to provide content for category viewer */ class GategoryProvider implements IStructuredContentProvider { /* (non-Javadoc) * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) */ public Object[] getElements(Object inputElement) { return SWMTCategorys.getInstance().getCategoryEntries().toArray(); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.IContentProvider#dispose() */ public void dispose() { // Not needed but needs to be implemented } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // Not used but needs to be implemented } }; /** * Creates group for Symbian agent options */ private void createSymbianAgentOptionsGroup() { Group closeSymbianGroup = new Group(container, SWT.SHADOW_NONE); closeSymbianGroup.setText("Symbian Agent Options"); GridLayout closegl = new GridLayout(2, false); GridData closegd = new GridData(GridData.FILL_BOTH); closeSymbianGroup.setLayout(closegl); closeSymbianGroup.setLayoutData(closegd); closeBetweenCyclesButton = new Button(closeSymbianGroup, SWT.CHECK); GridData closeLayoutData = new GridData(GridData.VERTICAL_ALIGN_END); closeBetweenCyclesButton.setLayoutData(closeLayoutData); closeBetweenCyclesButton.setToolTipText(CLOSE_MEM_SPY_BETWEEN_CYCLES_TIP_TEXT); boolean isToBeClosedBetweenCycles = MemSpyPreferences.isCloseSymbianAgentBetweenCyclesSelected(); closeBetweenCyclesButton.setSelection(isToBeClosedBetweenCycles); //Label for button, separate label is used because setting text to button wont align text to same vertical //position than next label. Label closeBetweenIntervalsLabel = new Label(closeSymbianGroup, SWT.LEFT); GridData closeBetweenLabelData = new GridData(GridData.VERTICAL_ALIGN_CENTER); closeBetweenIntervalsLabel.setText(CLOSE_MEM_SPY_BETWEEN_CYCLES_TEXT); closeBetweenIntervalsLabel.setLayoutData(closeBetweenLabelData); } /** * Creates group for Head Dumps */ private void createHeapDumpGroup() { // // Head dump group // Group headDumpGroup = new Group(container, SWT.SHADOW_NONE); headDumpGroup.setText("Heap Dumps During SWMT Logging"); GridLayout hdgl = new GridLayout(2, false); GridData hdgd = new GridData(GridData.FILL_BOTH); headDumpGroup.setLayout(hdgl); headDumpGroup.setLayoutData(hdgd); heapDumpBtn = new Button(headDumpGroup, SWT.CHECK); heapDumpBtn.setText("Get Heap Dumps for Threads to Analyse with Heap Analyser"); heapDumpBtn.setToolTipText("Set if Heap Dumps is to be received for Threads during SWMT logging"); heapDumpBtn.addSelectionListener(new HeadDumpSelectionListener()); heapDumpBtn.setSelection(MemSpyPreferences.isSWMTHeapDumpSelected()); GridData hdBtnGd = new GridData(); hdBtnGd.horizontalSpan = 2; heapDumpBtn.setLayoutData(hdBtnGd); //Label for Heap gategory limit Label heapTextLabel = new Label(headDumpGroup, SWT.LEFT); heapTextLabel.setText(HEAP_DATA_THREAD_FILTER_TXT + ":"); String heapFilterToolTipText = "When filter string is specified, only Threads that contain text specified will be tracked."; heapTextLabel.setToolTipText(heapFilterToolTipText); GridData heapTextLimitLayoutData = new GridData(GridData.VERTICAL_ALIGN_CENTER); heapTextLabel.setLayoutData(heapTextLimitLayoutData); //heap limit text heapText = new Text(headDumpGroup, SWT.LEFT | SWT.BORDER | SWT.BORDER); heapText.setTextLimit(120);//Text limit 128 specified in S60 side GridData heapTextLayoutData = new GridData(GridData.VERTICAL_ALIGN_CENTER); heapTextLayoutData.widthHint = 140; heapText.setLayoutData(heapTextLayoutData); heapText.setToolTipText(heapFilterToolTipText); if (heapDumpBtn.getSelection()) { heapText.setText(MemSpyPreferences.getSWMTHeapNameFilter()); } else { heapText.setEnabled(false); } } /** * Listener for Heap Dumps button, updates preferences and text in Heap Dumps group. */ private class HeadDumpSelectionListener implements SelectionListener { /* (non-Javadoc) * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetDefaultSelected(SelectionEvent e) { // not needed } /* * Change heapText and save preferences * (non-Javadoc) * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetSelected(SelectionEvent e) { boolean selection = heapDumpBtn.getSelection(); if (selection) { heapText.setEnabled(true); heapText.setText(MemSpyPreferences.getSWMTHeapNameFilter()); } else { heapText.setText(""); heapText.setEnabled(false); } } } /** * Save the heap filter text if enabled */ private void saveHeapFilterText() { //Check if heaptext is enabled, if it is, saving text to preferences if (heapText.isEnabled()) { String heapFilterText = heapText.getText().trim(); MemSpyPreferences.setSWMTHeapNameFilter(heapFilterText); } } /** * Save the Close between cycles selection */ private void saveCloseS60AgentBetweenCycles() { boolean selection = closeBetweenCyclesButton.getSelection(); // User selects to close MemSpy S60 application between cycles MemSpyPreferences.setCloseSymbianAgentBetweenCycles(selection); } /** * Save the heap dump selection */ private void saveHeapDumpSelection() { boolean selection = heapDumpBtn.getSelection(); MemSpyPreferences.setSWMTHeapDumpSelected(selection); } /** * Sets initial selection state for entries */ private void InitializeSelectionState() { int size = SWMTCategorys.getInstance().getCategoryEntries().size(); for (int i = 0; i < size; i++) { SWMTCategoryEntry entry = (SWMTCategoryEntry) categoryViewer.getElementAt(i); int isCategoryBitUp = categorySelection & entry.getCategoryId(); if (isCategoryBitUp != 0) { categoryViewer.setChecked(entry, true); } } } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.TitleAreaDialog#getInitialSize() */ protected Point getInitialSize() { return new Point(DIALOG_WIDTH, DIALOG_HEIGHT); } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.Dialog#create() */ public void create() { super.create(); // Currently just does creation by super call and stores status isCreateCalled = true; } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.Dialog#okPressed() */ protected void okPressed() { if (heapDumpBtn.getSelection()) { if (heapText.getText().trim().equals("")) { System.out.println("DEBUG: WARNING! Empty heap filter text!"); MessageBox box = new MessageBox(getShell(), SWT.ICON_WARNING | SWT.YES | SWT.NO); String warningMsg = "Empty \"" + HEAP_DATA_THREAD_FILTER_TXT + "\" field causes huge amount of data to be traced and tracing may take a very long time. " + "It is highly recommended to use \"" + HEAP_DATA_THREAD_FILTER_TXT + "\"." + "\n\nDo you want to continue anyway?"; box.setMessage(warningMsg); box.setText("Using \"" + HEAP_DATA_THREAD_FILTER_TXT + "\" is recommended"); int yes_no = box.open(); //If user does not want to continue but cancel, returning, otherwise just continue to save all data and exit if (yes_no == SWT.NO) { return; } } } saveHeapFilterText(); saveCloseS60AgentBetweenCycles(); saveHeapDumpSelection(); super.close(); } /* (non-Javadoc) * @see org.eclipse.jface.window.Window#open() */ public int open() { try { // Making sure that create is called if (!isCreateCalled) { create(); } showDefaultMessage(); } catch (Exception e) { e.printStackTrace(); } return super.open(); } /** * Resets possible error messages and show the default message. */ private void showDefaultMessage() { setErrorMessage(null); setMessage(DEFAULT_MESSAGE, IMessageProvider.INFORMATION); } /** * Informs user that parameters are valid and dialog can be * dismissed with OK button.. */ private void setCompleteOkMessage() { setErrorMessage(null); setMessage(COMPLETE_MESSAGE, IMessageProvider.INFORMATION); } /** * Shows error message in case no categories are selected. */ private void showErrorMessage() { setErrorMessage(ERROR_MESSAGE); setMessage(null); } /** * Disables OK button. * This method is guarded against call during construction * when button row has not been created yet and widget is <code>null</code>. */ private void disableOk() { if (okActionBtn != null) { okActionBtn.setEnabled(false); } } /** * Enables OK button. * This method is guarded against call during construction * when button row has not been created yet and widget is <code>null</code>. */ private void enableOk() { if (okActionBtn != null) { okActionBtn.setEnabled(true); } } /** * Updates buttons statuses according the current selection * status of table entry viewer contents and refreshes contents. */ private void notifySelectionChanged() { Object[] selectedCategoryEntries = getSelectedCategoryEntries(); if (selectedCategoryEntries.length > 0) { updateSelectedCategories(selectedCategoryEntries); enableOk(); setCompleteOkMessage(); } else { disableOk(); showErrorMessage(); } categoryViewer.refresh(); } /** * Creates checkbox viewer component for showing available SWMT categories. * @param parent Parent composite for the created composite. * @return New <code>CheckboxTableViewer</code> object instance. */ protected CheckboxTableViewer createCategoryCheckBoxTableViewer(Composite parent) { ArrayList<S60ToolsTableColumnData> columnDataArr = new ArrayList<S60ToolsTableColumnData>(); // // NOTE: Column indices must start from zero (0) and // the columns must be added in ascending numeric // order. // columnDataArr.add(new S60ToolsTableColumnData("Category", //$NON-NLS-1$ 350, SWMTCategoryEntry.NAME_COLUMN_INDEX, SWMTCategoryEntryTableViewerSorter.CRITERIA_NAME)); S60ToolsTableColumnData[] arr = columnDataArr.toArray(new S60ToolsTableColumnData[0]); S60ToolsTable tbl = S60ToolsTableFactory.createCheckboxTable(parent, arr); CheckboxTableViewer tblViewer = new CheckboxTableViewer(tbl.getTableInstance()); tbl.setHostingViewer(tblViewer); return tblViewer; } /** * Returns currently selected categories. * @return currently selected categories */ private Object[] getSelectedCategoryEntries() { return categoryViewer.getCheckedElements(); } /** * Stores currently selected categories combined with bitwise as a single integer. * @param selectedCategoryEntries array of selected category entries */ private void updateSelectedCategories(Object[] selectedCategoryEntries) { // Re-initializing category selection categorySelection = SWMTCategoryConstants.CATEGORY_NONE; for (int i = 0; i < selectedCategoryEntries.length; i++) { SWMTCategoryEntry categoryEntry = (SWMTCategoryEntry) selectedCategoryEntries[i]; categorySelection = categorySelection | categoryEntry.getCategoryId(); } } /** * Returns currently selected categories combined with bitwise as a single integer. * @return currently selected categories combined with bitwise as a single integer. */ public int getSelectedCategories() { return categorySelection; } }