sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.wizards/src/com/nokia/carbide/cpp/internal/pi/wizards/ui/ProfilerActivatorGroup.java
author Toni Pulkkinen <ext-toni.p.pulkkinen@nokia.com>
Wed, 23 Jun 2010 15:05:09 +0300
changeset 12 ae255c9aa552
permissions -rw-r--r--
Performance Investigator Carbide extension 2.4.0

/*
 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). 
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of the License "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.carbide.cpp.internal.pi.wizards.ui;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;

import com.nokia.carbide.cpp.internal.pi.plugin.model.ITrace;
import com.nokia.carbide.cpp.pi.PiPlugin;
import com.nokia.carbide.cpp.pi.export.ITraceProvider;
import com.nokia.carbide.cpp.pi.wizards.WizardsPlugin;
import com.nokia.s60tools.ui.preferences.PreferenceUtils;

/**
 * Provides functionality of the profiler activator
 */
public class ProfilerActivatorGroup extends AbstractBaseGroup {

	private TableViewer profileDataTable;
	private Composite rightButtonsComposite;
	private Label connectionNameInUseLabel;
	private IWizardContainer wizardContainer;
	private NewPIWizardPage wizardPage;
	private TraceHandler traceHandler;
	private PluginSelectionGroup pluginSelectionGroup;
	private Group settingsButtonGroup;
	private Button refreshListButton;
	private Button connectionSettingsButton;
	private Button tracingButton;

	/**
	 * Constructor
	 * 
	 * @param parent
	 *            instance of the parent composite
	 * @param wizardSettings
	 *            instance of the INewPIWizardSettings
	 * @param wizardPage
	 *            instance of the NewPIWizardPage
	 * @param wizardContainer
	 *            instance of the IWizardContainer
	 */
	public ProfilerActivatorGroup(Composite parent,
			INewPIWizardSettings wizardSettings, NewPIWizardPage wizardPage,
			IWizardContainer wizardContainer) {
		super(parent, wizardSettings, true);
		this.wizardContainer = wizardContainer;
		this.wizardPage = wizardPage;
		traceHandler = new TraceHandler(this);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.nokia.carbide.cpp.internal.pi.wizards.ui.AbstractBaseGroup#createContent
	 * ()
	 */
	protected void createContent() {
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 2;
		this.setLayout(gridLayout);
		this.setLayoutData(new GridData(GridData.FILL_BOTH));
		this.setText(Messages.getString("NewPIWizardPageInputTask.fromDevice")); //$NON-NLS-1$

		final Composite leftTables = new Composite(this, SWT.NONE);
		leftTables.setLayout(new GridLayout());
		leftTables.setLayoutData(new GridData(GridData.FILL_BOTH));
		pluginSelectionGroup = new PluginSelectionGroup(leftTables,
				wizardSettings, true);

		new Label(leftTables, SWT.NONE).setText(Messages
				.getString("ProfilerActivatorGroup.profilerDataTableTitle")); //$NON-NLS-1$
		profileDataTable = new TableViewer(leftTables, SWT.BORDER | SWT.SINGLE
				| SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);

		TableColumn column = new TableColumn(profileDataTable.getTable(),
				SWT.NONE);
		column.setText(Messages.getString("ProfilerActivatorGroup.columnName")); //$NON-NLS-1$
		column.setWidth(200);
		column.setResizable(true);
		column.setMoveable(true);
		column.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (!(e.widget instanceof TableColumn))
					return;
				((AbstractBaseSorter) profileDataTable.getSorter()).doSort(0);
				profileDataTable.refresh();

			}
		});

		column = new TableColumn(profileDataTable.getTable(), SWT.NONE);
		column.setText(Messages.getString("ProfilerActivatorGroup.columnTime")); //$NON-NLS-1$
		column.setWidth(120);
		column.setResizable(true);
		column.setMoveable(true);
		column.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (!(e.widget instanceof TableColumn))
					return;
				((AbstractBaseSorter) profileDataTable.getSorter()).doSort(1);
				profileDataTable.refresh();

			}
		});

		column = new TableColumn(profileDataTable.getTable(), SWT.NONE);
		column.setText(Messages.getString("ProfilerActivatorGroup.columnSize")); //$NON-NLS-1$
		column.setWidth(120);
		column.setResizable(true);
		column.setMoveable(true);
		column.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (!(e.widget instanceof TableColumn))
					return;
				((AbstractBaseSorter) profileDataTable.getSorter()).doSort(2);
				profileDataTable.refresh();

			}
		});

		GridData fileLogsTableGridData = new GridData(GridData.FILL_BOTH);
		fileLogsTableGridData.minimumHeight = 120;
		profileDataTable.getTable().setLayoutData(fileLogsTableGridData);
		profileDataTable.getTable().setHeaderVisible(true);
		profileDataTable.getTable().setLinesVisible(true);
		profileDataTable.setContentProvider(new IStructuredContentProvider() {
			public Object[] getElements(Object inputElement) {
				if (inputElement instanceof List<?>) {
					return ((List<?>) inputElement).toArray();
				}
				return new Object[0];
			}

			public void dispose() {
			}

			public void inputChanged(Viewer viewer, Object oldInput,
					Object newInput) {
			}

		});

		profileDataTable.setSorter(new AbstractBaseSorter(profileDataTable
				.getTable(), 0) {
			@Override
			public int compare(Viewer viewer, Object e1, Object e2) {
				ProfilerDataPlugins pdp1 = (ProfilerDataPlugins) e1;
				ProfilerDataPlugins pdp2 = (ProfilerDataPlugins) e2;
				int returnCode = 0;
				switch (column) {
				case 0:
					returnCode = pdp1
							.getProfilerDataPath()
							.lastSegment()
							.compareTo(pdp2.getProfilerDataPath().lastSegment());
					break;
				case 1:
					returnCode = compareNumber(pdp1.getTime(), pdp2.getTime());
					break;
				case 2:
					returnCode = compareNumber(pdp1.getSize(), pdp2.getSize());
					break;

				default:

					break;
				}
				if (!sortAscending)
					returnCode = -returnCode;
				return returnCode;
			}
		});

		profileDataTable.setLabelProvider(new AbstractLabelProvider() {
			public String getColumnText(Object element, int columnIndex) {
				ProfilerDataPlugins plugins = (ProfilerDataPlugins) element;

				switch (columnIndex) {
				case 0:
					return plugins.getProfilerDataPath().lastSegment();
				case 1:
					SimpleDateFormat formatter = new SimpleDateFormat("mm:ss"); //$NON-NLS-1$
					return formatter.format(new Date(plugins.getTime()));
				case 2:
					return String.valueOf((plugins.getSize() + 512) / 1024);
				default:
					break;
				}
				return ""; //$NON-NLS-1$
			}
		});

		rightButtonsComposite = new Composite(this, SWT.NONE);

		GridData rightButtonsCompositeGridData = new GridData(
				GridData.HORIZONTAL_ALIGN_FILL);
		rightButtonsComposite.setLayoutData(rightButtonsCompositeGridData);
		rightButtonsComposite.setLayout(new GridLayout());

		// Connection settings button
		settingsButtonGroup = new Group(rightButtonsComposite, SWT.NONE);
		settingsButtonGroup.setLayout(new GridLayout());
		settingsButtonGroup.setLayoutData(new GridData(GridData.FILL_BOTH));

		refreshListButton = new Button(settingsButtonGroup, SWT.PUSH);
		refreshListButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		refreshListButton.setText(Messages
				.getString("ProfilerActivatorGroup.refreshButtonName")); //$NON-NLS-1$
		refreshListButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				updatePlugins(traceHandler.fetchAvailablePlugins());
			}
		});

		connectionSettingsButton = new Button(settingsButtonGroup, SWT.PUSH);
		connectionSettingsButton.setLayoutData(new GridData(
				GridData.FILL_HORIZONTAL));
		connectionSettingsButton
				.setText(Messages
						.getString("ProfilerActivatorGroup.connectionSettingsButtonName")); //$NON-NLS-1$
		connectionSettingsButton.addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				Shell shell = PiPlugin.getCurrentlyActiveWbWindowShell();
				PreferenceUtils.openPreferencePage(PiPlugin.getTraceProvider()
						.getTraceSourcePreferencePageId(), shell);
				updateConnectionText();
			}
		});
		// Connection settings labels
		Label connectionTextLabel = new Label(settingsButtonGroup, SWT.LEFT);
		connectionTextLabel.setText(Messages
				.getString("ProfilerActivatorGroup.currentlyUsingTitle")); //$NON-NLS-1$
		connectionTextLabel.setLayoutData(new GridData(
				GridData.HORIZONTAL_ALIGN_CENTER));

		connectionNameInUseLabel = new Label(settingsButtonGroup, SWT.NONE);
		connectionNameInUseLabel.setLayoutData(new GridData(
				GridData.HORIZONTAL_ALIGN_CENTER));
		Group traceButtonGroup = new Group(rightButtonsComposite, SWT.NONE);
		traceButtonGroup.setLayout(new GridLayout());
		traceButtonGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
		new Label(traceButtonGroup, SWT.LEFT).setText(Messages
				.getString("ProfilerActivatorGroup.filePrefixTitle")); //$NON-NLS-1$
		final Text filePrefixText = new Text(traceButtonGroup, SWT.BORDER);
		filePrefixText.setText("PIProfiler_#"); //$NON-NLS-1$
		filePrefixText.setLayoutData(new GridData(GridData.FILL_BOTH));

		// Start/Stop tracing button
		tracingButton = new Button(traceButtonGroup, SWT.PUSH);
		tracingButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		tracingButton.setText(Messages
				.getString("ProfilerActivatorGroup.startTracingButtonName")); //$NON-NLS-1$
		tracingButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (PiPlugin.getTraceProvider().isListening()) {
					addTraceFile(traceHandler.stopTrace());
				} else {
					traceHandler.startTrace(filePrefixText.getText(),
							pluginSelectionGroup.getSelectedPluginIds());
				}
				updateButtons();
			}
		});

	}

	/**
	 * Compare two long number
	 * 
	 * @param one
	 * @param two
	 * @return result of the comparison
	 */
	private int compareNumber(long one, long two) {
		if (one > two) {
			return 1;
		} else if (one < two) {
			return -1;
		} else {
			return 0;
		}
	}

	/**
	 * updateConnectionText updates connection text to match used settings
	 */
	private void updateConnectionText(boolean forceUpdate) {
		traceHandler.updateCurrenConnection();
		if (pluginSelectionGroup.getSelectedPluginIds().length <= 0
				|| forceUpdate) {
			updatePlugins(traceHandler.fetchAvailablePlugins());
		}
	}
	
	/**
	 * updateConnectionText updates connection text to match used settings
	 */
	private void updateConnectionText() {
		traceHandler.updateCurrenConnection();
	}

	/**
	 * Set current connection name
	 * 
	 * @param connection
	 *            the current connection name
	 */
	public void setCurrentConnection(final String connection) {
		Display.getDefault().syncExec(new Runnable() {
			public void run() {
				connectionNameInUseLabel.setText(connection);
				getParent().layout(true, true);
			}
		});

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.nokia.carbide.cpp.internal.pi.wizards.ui.AbstractBaseGroup#getTable()
	 */
	@Override
	public Table getTable() {
		return profileDataTable.getTable();
	}

	@Override
	public IStatus validateContent(NewPIWizard wizardPage) {
		List<ProfilerDataPlugins> dataFiles = getProfilerDataFiles();
		if (dataFiles != null && dataFiles.size() > 0) {
			wizardPage.setProfilerDataFiles(getProfilerDataFiles());
			return Status.OK_STATUS;
		} else {
			return new Status(
					Status.INFO,
					WizardsPlugin.PLUGIN_ID,
					Messages
							.getString("ProfilerActivatorGroup.profilerGroupDescription")); //$NON-NLS-1$
		}

	}

	@Override
	public void setVisible(boolean visible) {
		if (visible) {
			updateConnectionText(false);
		}
		super.setVisible(visible);

	}

	private void updatePlugins(final List<ITrace> plugins) {
		pluginSelectionGroup.updateTraceIds(new ProfilerDataPlugins(
				new Path(""), plugins)); //$NON-NLS-1$
		updateButtons();
	}

	/**
	 * Add given trace data file to profiler data file table
	 * 
	 * @param path
	 */
	private void addTraceFile(final IPath path) {
		if (path == null) {
			return;
		}
		ProfilerDataPlugins dataPlugins = removeWithPath(path
				.removeFileExtension().addFileExtension(
						ITraceProvider.BASE_FILE));
		if (dataPlugins != null) {
			try {
				addProfilerDataFile(path, dataPlugins.getTime(), path.toFile()
						.length());
				refreshTable(profileDataTable, true);
			} catch (Exception e) {
				wizardPage
						.setErrorMessage(e.getMessage()
								+ " " + Messages.getString("ProfilerActivatorGroup.tryDeselectPluginsFromList")); //$NON-NLS-1$ //$NON-NLS-2$
				wizardPage.setPageComplete(false);
				refreshTable(profileDataTable, false);
				path.toFile().delete();
			}
		}
	}

	public NewPIWizardPage getWizardPage() {
		return wizardPage;
	}

	public IWizardContainer getWizardContainer() {
		return wizardContainer;
	}

	/**
	 * Update trace data files
	 * 
	 * @param path
	 * @param time
	 * @param size
	 */
	public void updateTraceDataFile(final IPath path, final long time,
			final long size) {
		Display.getDefault().syncExec(new Runnable() {
			public void run() {
				// remove if both time and size are -1
				if (time == -1 && size == -1) {
					removeWithPath(path);
				} else {
					updateProfilerDataFile(path, time, size);
				}
				refreshTable(profileDataTable, false);
			}
		});
	}

	/**
	 * Update buttons
	 */
	public void updateButtons() {
		if (PiPlugin.getTraceProvider().isListening()) {
			wizardPage.setErrorMessage(null);
			refreshListButton.setEnabled(false);
			connectionSettingsButton.setEnabled(false);
			((NewPIWizardPageInputTask) wizardPage)
					.setButtonGroupEnabled(false);
			tracingButton.setText(Messages
					.getString("ProfilerActivatorGroup.stopTracingButtonName")); //$NON-NLS-1$
		} else {
			refreshListButton.setEnabled(true);
			connectionSettingsButton.setEnabled(true);
			((NewPIWizardPageInputTask) wizardPage).setButtonGroupEnabled(true);
			tracingButton
					.setText(Messages
							.getString("ProfilerActivatorGroup.startTracingButtonName")); //$NON-NLS-1$
		}

		if (pluginSelectionGroup.getSelectedPluginIds().length <= 0) {
			tracingButton.setEnabled(false);
		} else {
			tracingButton.setEnabled(true);
		}
	}

	/**
	 * Generate next dat file name
	 * 
	 * @param path
	 * @return
	 */
	private IPath generateDatFile(IPath path) {
		while (path.toFile().exists()) {
			String file = path.lastSegment();
			String fileExtension = path.getFileExtension();
			file = file.substring(0, file.lastIndexOf("." + fileExtension)); //$NON-NLS-1$
			int index = file.lastIndexOf("_"); //$NON-NLS-1$
			if (index != -1) {
				try {
					int count = Integer.valueOf(file.substring(index + 1));
					count++;
					file = file.substring(0, index + 1) + count;
					path = path.removeLastSegments(1).append(
							file + "." + fileExtension); //$NON-NLS-1$
				} catch (Exception e) {
					path = path.removeLastSegments(1).append(
							file + "_0." + fileExtension); //$NON-NLS-1$
				}

			} else {
				path = path.removeLastSegments(1).append(
						file + "_0." + fileExtension); //$NON-NLS-1$
			}
		}
		return path;

	}

	/**
	 * Handle temporary profiler data files in case user is tried to close
	 * wizard and user has traced some data from device
	 * 
	 * @param forceRemove
	 */
	public void handleTemporaryProfilerDataFiles(boolean forceRemove) {
		final List<ProfilerDataPlugins> plugins = new ArrayList<ProfilerDataPlugins>();
		plugins.addAll(getProfilerDataFiles());
		getProfilerDataFiles().clear();
		if (forceRemove) {
			deleteProfilerDataFiles(plugins);
		} else if (plugins.size() > 0) {
			boolean answer = MessageDialog
					.openQuestion(
							Display.getDefault().getActiveShell(),
							Messages
									.getString("ProfilerActivatorGroup.questionDialogTitle"), Messages.getString("ProfilerActivatorGroup.questionDialogMessage")); //$NON-NLS-1$ //$NON-NLS-2$
			if (answer) {
				// open file dialog for selecting a crash file
				DirectoryDialog dialog = new DirectoryDialog(Display
						.getDefault().getActiveShell());
				dialog
						.setText(Messages
								.getString("ProfilerActivatorGroup.directorySelectionDialogTitle")); //$NON-NLS-1$
				final String result = dialog.open();
				if (result != null) {
					WorkspaceJob job = new WorkspaceJob(
							Messages
									.getString("ProfilerActivatorGroup.movingProfilerDataFilesJob") + result) { //$NON-NLS-1$
						@Override
						public IStatus runInWorkspace(IProgressMonitor monitor)
								throws CoreException {
							monitor.beginTask("", IProgressMonitor.UNKNOWN); //$NON-NLS-1$
							for (ProfilerDataPlugins plugin : plugins) {
								IPath dataFile = plugin.getProfilerDataPath();
								IPath targetFile = generateDatFile(new Path(
										result).append(dataFile.lastSegment()));
								try {
									moveFile(dataFile, targetFile,
											new SubProgressMonitor(monitor,
													IProgressMonitor.UNKNOWN));
								} catch (Exception e) {
									List<ProfilerDataPlugins> list = new ArrayList<ProfilerDataPlugins>();
									list.add(plugin);
									deleteProfilerDataFiles(list);
									e.printStackTrace();
									MessageDialog
											.openError(
													getShell(),
													Messages
															.getString("ProfilerActivatorGroup.errorDialogTitle"), MessageFormat.format(Messages.getString("ProfilerActivatorGroup.failedToMoveFileTo"), dataFile.lastSegment(), result)); //$NON-NLS-1$ //$NON-NLS-2$
								}
							}
							monitor.done();
							return Status.OK_STATUS;
						}
					};
					job.schedule();
				} else {
					deleteProfilerDataFiles(plugins);
				}
			} else {
				deleteProfilerDataFiles(plugins);
			}
		}
	}

	/**
	 * Delete profiler data files
	 * 
	 * @param plugins
	 */
	private void deleteProfilerDataFiles(final List<ProfilerDataPlugins> plugins) {
		WorkspaceJob job = new WorkspaceJob(Messages
				.getString("ProfilerActivatorGroup.removeProfilerDataFilesJob")) { //$NON-NLS-1$

			@Override
			public IStatus runInWorkspace(IProgressMonitor monitor)
					throws CoreException {
				monitor.beginTask("", IProgressMonitor.UNKNOWN); //$NON-NLS-1$
				for (ProfilerDataPlugins plugin : plugins) {
					IPath dataFile = plugin.getProfilerDataPath();
					monitor
							.setTaskName(MessageFormat
									.format(
											Messages
													.getString("ProfilerActivatorGroup.deletingProfilerDataFiles"), dataFile.lastSegment())); //$NON-NLS-1$
					if (dataFile.toFile().exists()) {
						while (!dataFile.toFile().delete()) {
							if (monitor.isCanceled()) {
								break;
							}
							try {
								Thread.sleep(1000);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}

				}
				;
				monitor.done();
				return Status.OK_STATUS;
			}

		};
		job.schedule();

	}

	/**
	 * Move profiler data file from temporary location to user selected target
	 * 
	 * @param source
	 * @param target
	 * @param monitor
	 * @throws IOException
	 */
	private void moveFile(final IPath source, IPath target,
			IProgressMonitor monitor) throws IOException {
		if (monitor == null) {
			monitor = new NullProgressMonitor();
		}
		InputStream in = null;
		OutputStream out = null;
		try {
			monitor
					.beginTask(
							MessageFormat
									.format(
											Messages
													.getString("ProfilerActivatorGroup.copyingProfilerDataFiles"), source.lastSegment(), target.removeLastSegments(1)), IProgressMonitor.UNKNOWN); //$NON-NLS-1$
			in = new FileInputStream(source.toFile());
			out = new FileOutputStream(target.toFile());
			int bufferSize = 1024;
			byte[] buf = new byte[bufferSize];
			int len;
			while ((len = in.read(buf)) > 0) {
				out.write(buf, 0, len);
				out.flush();
			}

		} finally {
			if (in != null) {
				in.close();
			}
			if (out != null) {
				out.close();
			}
			monitor
					.setTaskName(MessageFormat
							.format(
									Messages
											.getString("ProfilerActivatorGroup.deletingProfilerDataFiles"), source.lastSegment())); //$NON-NLS-1$
			while (!source.toFile().delete()) {
				if (monitor.isCanceled()) {
					break;
				}
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			monitor.done();
		}
	}
}