org.eclipse.jubula.client.ui.rcp.properties.ProjectGeneralPropertyPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jubula.client.ui.rcp.properties.ProjectGeneralPropertyPage.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2010 BREDEX GmbH.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     BREDEX GmbH - initial API and implementation and/or initial documentation
 *******************************************************************************/
package org.eclipse.jubula.client.ui.rcp.properties;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityNotFoundException;

import org.apache.commons.lang.StringUtils;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.window.Window;
import org.eclipse.jubula.client.core.businessprocess.ProjectNameBP;
import org.eclipse.jubula.client.core.events.DataChangedEvent;
import org.eclipse.jubula.client.core.events.DataEventDispatcher;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.DataState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.ProjectState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.UpdateState;
import org.eclipse.jubula.client.core.model.INodePO;
import org.eclipse.jubula.client.core.model.IPersistentObject;
import org.eclipse.jubula.client.core.model.IProjectPO;
import org.eclipse.jubula.client.core.model.IProjectPropertiesPO;
import org.eclipse.jubula.client.core.model.IReusedProjectPO;
import org.eclipse.jubula.client.core.model.PoMaker;
import org.eclipse.jubula.client.core.persistence.EditSupport;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.client.core.persistence.NodePM;
import org.eclipse.jubula.client.core.persistence.PMException;
import org.eclipse.jubula.client.core.persistence.ProjectPM;
import org.eclipse.jubula.client.core.utils.TrackingUnit;
import org.eclipse.jubula.client.ui.constants.ContextHelpIds;
import org.eclipse.jubula.client.ui.rcp.Plugin;
import org.eclipse.jubula.client.ui.rcp.businessprocess.CompletenessBP;
import org.eclipse.jubula.client.ui.rcp.controllers.PMExceptionHandler;
import org.eclipse.jubula.client.ui.rcp.factory.ControlFactory;
import org.eclipse.jubula.client.ui.rcp.handlers.project.RefreshProjectHandler;
import org.eclipse.jubula.client.ui.rcp.i18n.Messages;
import org.eclipse.jubula.client.ui.rcp.provider.ControlDecorator;
import org.eclipse.jubula.client.ui.rcp.search.query.DeprecatedModulesQuery;
import org.eclipse.jubula.client.ui.rcp.widgets.CheckedIntText;
import org.eclipse.jubula.client.ui.rcp.widgets.CheckedProjectNameText;
import org.eclipse.jubula.client.ui.rcp.widgets.CheckedSignatureText;
import org.eclipse.jubula.client.ui.rcp.widgets.CheckedText;
import org.eclipse.jubula.client.ui.utils.ErrorHandlingUtil;
import org.eclipse.jubula.client.ui.utils.LayoutUtil;
import org.eclipse.jubula.client.ui.widgets.DirectCombo;
import org.eclipse.jubula.client.ui.widgets.UIComponentHelper;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.exception.Assert;
import org.eclipse.jubula.tools.internal.exception.JBException;
import org.eclipse.jubula.tools.internal.exception.ProjectDeletedException;
import org.eclipse.jubula.tools.internal.i18n.I18n;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
import org.eclipse.jubula.tools.internal.utils.EnvironmentUtils;
import org.eclipse.search.ui.NewSearchUI;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
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.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This is the class for the test data property page of a project.
 *
 * @author BREDEX GmbH
 * @created 08.02.2005
 */
public class ProjectGeneralPropertyPage extends AbstractProjectPropertyPage {
    /**
     * @author BREDEX GmbH
     * @created Aug 21, 2007
     */
    public interface IOkListener {
        /**
         * The OK button has been pressed.
         */
        public void okPressed() throws PMException;
    }

    /** number of columns = 1 */
    private static final int NUM_COLUMNS_1 = 1;
    /** number of columns = 2 */
    private static final int NUM_COLUMNS_2 = 2;
    /** number of columns = 2 */
    private static final int NUM_COLUMNS_3 = 3;

    /** the logger */
    private static Logger log = LoggerFactory.getLogger(ProjectGeneralPropertyPage.class);

    /** the m_text field for the project name */
    private CheckedText m_projectNameTextField;
    /** the m_isReusable checkbox for if the project is reusable */
    private Button m_isReusableCheckbox;
    /** the m_isProtected checkbox for if the project is protected */
    private Button m_isProtectedCheckbox;
    /** the StateController */
    private final WidgetModifyListener m_modifyListener = new WidgetModifyListener();
    /** the StateController */
    private final ToolkitComboSelectionListener m_toolkitComboListener = new ToolkitComboSelectionListener();
    /** the Combo to select the toolkit */
    private DirectCombo<String> m_projectToolkitCombo;

    /** the StateController for the markup combo */
    private final MarkupComboSelectionListener m_markupComboListener = new MarkupComboSelectionListener();
    /** the combo to select the MarkupLanguate */
    private DirectCombo<String> m_projectMarkupCombo;
    /** the new project name */
    private String m_newProjectName;

    /**  Checkbox to decide if testresults should be deleted after specified days */
    private Button m_cleanTestresults = null;
    /**  textfield to specify days after which testresults should be deleted after from database */
    private CheckedIntText m_cleanResultDays = null;

    /**  Checkbox to decide if certain changes to the project should be tracked */
    private Button m_isTrackingActivatedButton = null;
    /**  group to specify how long changes should be stored */
    private Group m_trackChangesTimespanSelection = null;
    /**  textfield to specify how long tracked changes should be stored */
    private CheckedIntText m_trackChangesSpan = null;
    /**  textfield to specify what should be stored to identify who made a change */
    private Composite m_trackChangesUnitSelection = null;
    /**  group to specify what should be stored to identify who made a change */
    private Group m_trackChangesSignatureSelection = null;
    /**  textfield to specify what should be stored to identify who made a change */
    private CheckedSignatureText m_trackChangesSignature = null;
    /**  button to delete all tracked changes */
    private Button m_deleteChanges = null;

    /** set of listeners to be informed when ok has been pressed */
    private Set<IOkListener> m_okListenerList = new HashSet<IOkListener>();
    /**
     * the projects description text field
     */
    private Text m_projectDescriptionTextField;

    /**
     * the original / unmodified project properties
     */
    private IProjectPropertiesPO m_origProjectProps;
    /**
     * the old project name
     */
    private String m_oldProjectName;

    /**
     * @param es
     *            the editSupport
     */
    public ProjectGeneralPropertyPage(EditSupport es) {
        super(es);
        m_oldProjectName = getProject().getName();
        m_origProjectProps = ((IProjectPropertiesPO) es.getOriginal());
    }

    /**
     * {@inheritDoc}
     */
    protected Control createContents(Composite parent) {
        Composite composite = createComposite(parent, NUM_COLUMNS_1, GridData.FILL, false);
        Composite projectNameComposite = createComposite(composite, NUM_COLUMNS_2, GridData.FILL, false);
        noDefaultAndApplyButton();

        createEmptyLabel(projectNameComposite);
        createEmptyLabel(projectNameComposite);

        createProjectNameField(projectNameComposite);
        createProjectDescrField(projectNameComposite);
        createProjectVersionInfo(projectNameComposite);
        createProjectGuidInfo(projectNameComposite);

        createEmptyLabel(projectNameComposite);
        separator(projectNameComposite, NUM_COLUMNS_2);
        createEmptyLabel(projectNameComposite);

        createAutToolKit(projectNameComposite);
        createMarkupLanguage(projectNameComposite);
        separator(projectNameComposite, NUM_COLUMNS_2);
        createEmptyLabel(projectNameComposite);

        createIsReusable(projectNameComposite);
        createIsProtected(projectNameComposite);

        separator(projectNameComposite, NUM_COLUMNS_2);
        createEmptyLabel(projectNameComposite);

        createCleanTestResults(projectNameComposite);

        separator(projectNameComposite, NUM_COLUMNS_2);
        createTrackChangesEnablement(projectNameComposite);
        Composite trackChangesProperties = createComposite(composite, NUM_COLUMNS_3, GridData.FILL, false);
        createTrackChangesTimespanSelection(trackChangesProperties);
        createTrackChangesSignatureSelection(trackChangesProperties);
        createTrackChangesDeleteDataButton(trackChangesProperties);

        Composite innerComposite = new Composite(composite, SWT.NONE);
        GridLayout compositeLayout = new GridLayout();
        compositeLayout.numColumns = NUM_COLUMNS_1;
        compositeLayout.marginHeight = 0;
        compositeLayout.marginWidth = 0;
        innerComposite.setLayout(compositeLayout);
        GridData compositeData = new GridData();
        compositeData.horizontalSpan = NUM_COLUMNS_2;
        compositeData.horizontalAlignment = GridData.FILL;
        compositeData.grabExcessHorizontalSpace = true;
        innerComposite.setLayoutData(compositeData);

        addListener();
        Plugin.getHelpSystem().setHelp(parent, ContextHelpIds.PROJECT_PROPERTY_PAGE);
        return composite;
    }

    /**
     * @param parent the parent composite
     */
    private void createProjectVersionInfo(Composite parent) {
        Composite leftComposite = createComposite(parent, NUM_COLUMNS_1, GridData.BEGINNING, false);
        Composite rightComposite = createComposite(parent, 3, GridData.FILL, true);

        createLabel(leftComposite, Messages.ProjectPropertyPageProjectVersion);

        Text versionText = new Text(rightComposite, SWT.WRAP);
        GridData labelGrid = new GridData(GridData.FILL, GridData.CENTER, true, false, 1, 1);
        labelGrid.widthHint = 124;
        versionText.setLayoutData(labelGrid);
        versionText.setText(getProject().getVersionString());
        versionText.setEditable(false);
        versionText.setBackground(rightComposite.getBackground());
    }

    /**
     * @param parent the parent composite
     */
    private void createProjectGuidInfo(Composite parent) {
        Composite leftComposite = createComposite(parent, NUM_COLUMNS_1, GridData.BEGINNING, false);
        Composite rightComposite = createComposite(parent, 3, GridData.FILL, true);

        ControlDecorator.createInfo(createLabel(leftComposite, Messages.ProjectPropertyPageProjectGuid),
                I18n.getString("ControlDecorator.ProjectPropertiesGUID"), false); //$NON-NLS-1$

        Text guidText = new Text(rightComposite, SWT.WRAP);
        GridData labelGrid = new GridData(GridData.FILL, GridData.CENTER, true, false, 1, 1);
        labelGrid.widthHint = 124;
        guidText.setLayoutData(labelGrid);
        guidText.setText(getProject().getGuid());
        guidText.setEditable(false);
        guidText.setBackground(rightComposite.getBackground());
    }

    /**
     * @param parent
     *            the parent composite
     */
    private void createIsReusable(Composite parent) {
        Composite leftComposite = createComposite(parent, NUM_COLUMNS_1, GridData.BEGINNING, false);
        Composite rightComposite = createComposite(parent, NUM_COLUMNS_2, GridData.FILL, true);
        ControlDecorator.createInfo(createLabel(leftComposite, Messages.ProjectPropertyPageIsReusable),
                I18n.getString("ControlDecorator.NewProjectIsReusable"), false); //$NON-NLS-1$
        m_isReusableCheckbox = new Button(rightComposite, SWT.CHECK);

        m_isReusableCheckbox.setSelection(m_origProjectProps.getIsReusable());
        m_isReusableCheckbox.addSelectionListener(new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                boolean isReusable = m_isReusableCheckbox.getSelection();
                if (isReusable) {
                    m_isProtectedCheckbox.setSelection(true);
                }
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                widgetSelected(e);
            }
        });
    }

    /**
     * @param parent
     *            the parent composite
     */
    private void createIsProtected(Composite parent) {
        Composite leftComposite = createComposite(parent, NUM_COLUMNS_1, GridData.BEGINNING, false);
        Composite rightComposite = createComposite(parent, NUM_COLUMNS_2, GridData.FILL, true);
        ControlDecorator.createInfo(createLabel(leftComposite, Messages.ProjectPropertyPageIsProtected),
                I18n.getString("ControlDecorator.NewProjectIsProtected"), //$NON-NLS-1$
                false);
        m_isProtectedCheckbox = new Button(rightComposite, SWT.CHECK);

        m_isProtectedCheckbox.setSelection(m_origProjectProps.getIsProtected());

    }

    /**
     * Creates the textfield for the project name.
     * 
     * @param parent
     *            The parent composite.
     */
    private void createProjectNameField(Composite parent) {
        Composite leftComposite = createComposite(parent, NUM_COLUMNS_1, GridData.BEGINNING, false);
        Composite rightComposite = createComposite(parent, NUM_COLUMNS_1, GridData.FILL, true);
        createLabel(leftComposite, Messages.ProjectPropertyPageProjectName);
        m_projectNameTextField = new CheckedProjectNameText(rightComposite, SWT.BORDER);
        m_projectNameTextField.setText(getProject().getName());
        GridData textGridData = new GridData();
        textGridData.grabExcessHorizontalSpace = true;
        textGridData.horizontalAlignment = GridData.FILL;
        LayoutUtil.addToolTipAndMaxWidth(textGridData, m_projectNameTextField);
        m_projectNameTextField.setLayoutData(textGridData);
        LayoutUtil.setMaxChar(m_projectNameTextField);
    }

    /**
     * Creates the textfield for the project description.
     * 
     * @param parent
     *            The parent composite.
     */
    private void createProjectDescrField(Composite parent) {
        Composite leftComposite = createComposite(parent, NUM_COLUMNS_1, GridData.BEGINNING, false);
        Composite rightComposite = createComposite(parent, NUM_COLUMNS_1, GridData.FILL, true);
        createLabel(leftComposite, Messages.ProjectPropertyPageProjectDescr);
        m_projectDescriptionTextField = new Text(rightComposite, SWT.BORDER);
        m_projectDescriptionTextField.setText(StringUtils.defaultString(getProject().getComment()));
        GridData textGridData = new GridData();
        textGridData.grabExcessHorizontalSpace = true;
        textGridData.horizontalAlignment = GridData.FILL;
        LayoutUtil.addToolTipAndMaxWidth(textGridData, m_projectDescriptionTextField);
        m_projectDescriptionTextField.setLayoutData(textGridData);
        LayoutUtil.setMaxChar(m_projectDescriptionTextField, IPersistentObject.MAX_STRING_LENGTH);
    }

    /**
     * @param parent the parent composite
     */
    private void createMarkupLanguage(Composite parent) {
        Composite leftComposite = createComposite(parent, NUM_COLUMNS_1, GridData.BEGINNING, false);
        Composite rightComposite = createComposite(parent, NUM_COLUMNS_2, GridData.FILL, true);
        Label label = createLabel(leftComposite, Messages.ProjectPropertyPageMarkupLanguageLabel);
        ControlDecorator.createInfo(label, Messages.ProjectPropertyPageMarkupLanguageInfo, false);
        m_projectMarkupCombo = ControlFactory.createProjectMarkupLanguageCombo(rightComposite);

        GridData textGridData = new GridData();
        textGridData.grabExcessHorizontalSpace = true;
        textGridData.horizontalAlignment = GridData.FILL;
        m_projectToolkitCombo.setLayoutData(textGridData);
    }

    /**
     * @param parent the parent composite
     */
    private void createAutToolKit(Composite parent) {
        Composite leftComposite = createComposite(parent, NUM_COLUMNS_1, GridData.BEGINNING, false);
        Composite rightComposite = createComposite(parent, NUM_COLUMNS_2, GridData.FILL, true);
        createLabel(leftComposite, Messages.ProjectPropertyPageAutToolKitLabel);
        m_projectToolkitCombo = ControlFactory.createProjectToolkitCombo(rightComposite);
        m_projectToolkitCombo.setSelectedObject(getProject().getToolkit());
        GridData textGridData = new GridData();
        textGridData.grabExcessHorizontalSpace = true;
        textGridData.horizontalAlignment = GridData.FILL;
        m_projectToolkitCombo.setLayoutData(textGridData);
    }

    /**
     * reflect the enablement of checkbox to the corresponding textfield
     */
    protected void enableCleanResultDaysTextfield() {
        enableSelectionAndEnablementDependent(m_cleanTestresults, m_cleanResultDays);
    }

    /**
     * @param parent The parent <code>Composite</code>
     */
    private void createCleanTestResults(Composite parent) {
        m_cleanTestresults = new Button(parent, SWT.CHECK);
        m_cleanTestresults.setText(Messages.TestResultViewPreferencePageCleanResults);
        GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
        gridData.horizontalSpan = 1;
        gridData.grabExcessHorizontalSpace = false;
        m_cleanTestresults.setLayoutData(gridData);
        int testResultCleanupInterval = getProject().getTestResultCleanupInterval();
        m_cleanTestresults.setSelection(testResultCleanupInterval != IProjectPO.NO_CLEANUP);
        m_cleanTestresults.addSelectionListener(new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                enableCleanResultDaysTextfield();
                checkCompleteness();
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                // nothing here
            }
        });
        m_cleanResultDays = new CheckedIntText(parent, SWT.BORDER, false, 1, Integer.MAX_VALUE);
        gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
        gridData.horizontalSpan = 1;
        gridData.grabExcessHorizontalSpace = false;
        gridData.widthHint = 80;
        m_cleanResultDays.setLayoutData(gridData);
        if (testResultCleanupInterval > 0) {
            m_cleanResultDays.setText(String.valueOf(testResultCleanupInterval));
        }
        m_cleanResultDays.addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                // nothing
            }

            public void keyReleased(KeyEvent e) {
                checkCompleteness();
            }

        });
        enableCleanResultDaysTextfield();
        ControlDecorator.createInfo(m_cleanResultDays,
                I18n.getString("TestResultViewPreferencePage.cleanResultsInfo"), //$NON-NLS-1$
                false);
    }

    /**
     * @param parent The parent <code>Composite</code>
     */
    private void createTrackChangesEnablement(Composite parent) {
        m_isTrackingActivatedButton = new Button(parent, SWT.CHECK);
        m_isTrackingActivatedButton.setText(Messages.PrefPageTrackChanges);
        m_isTrackingActivatedButton.setSelection(m_origProjectProps.getIsTrackingActivated());
        GridData gridData = new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false);
        gridData.horizontalSpan = 2;
        gridData.grabExcessHorizontalSpace = false;
        m_isTrackingActivatedButton.setLayoutData(gridData);
        ControlDecorator.createInfo(m_isTrackingActivatedButton,
                I18n.getString("TestResultViewPreferencePage.TrackChangesInfo"), //$NON-NLS-1$
                false);

        m_isTrackingActivatedButton.addSelectionListener(new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                if (m_isTrackingActivatedButton != null) {
                    UIComponentHelper.setEnabledRecursive(m_trackChangesTimespanSelection,
                            m_isTrackingActivatedButton.getSelection());
                    UIComponentHelper.setEnabledRecursive(m_trackChangesSignatureSelection,
                            m_isTrackingActivatedButton.getSelection());

                    if (!m_isTrackingActivatedButton.getSelection()) {
                        m_trackChangesSpan.setBackground(null);
                    } else {
                        m_trackChangesSpan.validate();
                    }
                }
                checkCompleteness();
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                // nothing here
            }
        });
    }

    /**
     * @param parent The parent <code>Composite</code>
     */
    private void createTrackChangesTimespanSelection(Composite parent) {
        m_trackChangesTimespanSelection = new Group(parent, SWT.NONE);
        GridData gridData = new GridData(GridData.FILL_BOTH);
        m_trackChangesTimespanSelection.setLayout(new GridLayout());
        m_trackChangesTimespanSelection.setLayoutData(gridData);
        m_trackChangesTimespanSelection.setText(Messages.PrefPageTrackChangesTimespanSelectionText);
        m_trackChangesUnitSelection = new Composite(m_trackChangesTimespanSelection, SWT.NULL);
        m_trackChangesUnitSelection.setLayout(new GridLayout());

        Button daysButton = new Button(m_trackChangesUnitSelection, SWT.RADIO);
        daysButton.setText("Days"); //$NON-NLS-1$
        Button changesButton = new Button(m_trackChangesUnitSelection, SWT.RADIO);
        changesButton.setText("Changes"); //$NON-NLS-1$
        SelectionListener listener = new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                checkCompleteness();
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                checkCompleteness();
            }
        };
        daysButton.addSelectionListener(listener);
        changesButton.addSelectionListener(listener);

        TrackingUnit unit = m_origProjectProps.getTrackChangesUnit();
        if (unit != null) {
            switch (unit) {
            case CHANGES:
                changesButton.setSelection(true);
                break;
            case DAYS:
                daysButton.setSelection(true);
                break;
            default:
                break;
            }
        } else {
            daysButton.setSelection(true); // set days as default
        }

        m_trackChangesSpan = new CheckedIntText(m_trackChangesTimespanSelection, SWT.BORDER, false, 1,
                Integer.MAX_VALUE);
        gridData = new GridData(SWT.BEGINNING, SWT.NONE, true, true);
        gridData.widthHint = 80;
        m_trackChangesSpan.setLayoutData(gridData);
        ControlDecorator.createInfo(m_trackChangesSpan,
                I18n.getString("TestResultViewPreferencePage.cleanResultsTimeunitInfo"), //$NON-NLS-1$
                false);

        Integer span = m_origProjectProps.getTrackChangesSpan();
        if (span != null) {
            m_trackChangesSpan.setText(String.valueOf(span));
        } else {
            // set 10 as default
            m_trackChangesSpan.setText("10"); //$NON-NLS-1$
        }
        m_trackChangesSpan.addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                // nothing
            }

            public void keyReleased(KeyEvent e) {
                checkCompleteness();
            }
        });
        if (m_isTrackingActivatedButton != null) {
            UIComponentHelper.setEnabledRecursive(m_trackChangesTimespanSelection,
                    m_isTrackingActivatedButton.getSelection());
        }
        m_trackChangesSpan.setBackground(null);
    }

    /**
     * @param parent The parent <code>Composite</code>
     */
    private void createTrackChangesSignatureSelection(Composite parent) {
        m_trackChangesSignatureSelection = new Group(parent, SWT.NONE);
        m_trackChangesSignatureSelection.setLayout(new GridLayout());
        GridData gridData = new GridData(GridData.FILL_BOTH);
        gridData.horizontalSpan = 2;
        gridData.grabExcessHorizontalSpace = true;
        m_trackChangesSignatureSelection.setLayoutData(gridData);
        m_trackChangesSignatureSelection.setText(Messages.PrefPageTrackChangesSignatureSelectionText);
        Label label = new Label(m_trackChangesSignatureSelection, SWT.WRAP);
        label.setText(Messages.PrefPageTrackChangesSignatureDescription);
        final GridData labelData = new GridData();
        labelData.horizontalSpan = 2;
        labelData.grabExcessHorizontalSpace = false;
        labelData.horizontalAlignment = SWT.LEFT;
        labelData.widthHint = 400;
        label.setLayoutData(labelData);

        m_trackChangesSignature = new CheckedSignatureText(m_trackChangesSignatureSelection, SWT.BORDER);
        gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
        gridData.widthHint = 200;
        m_trackChangesSignature.setLayoutData(gridData);
        m_trackChangesSignature.addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                // nothing
            }

            public void keyReleased(KeyEvent e) {
                checkCompleteness();
            }
        });

        String signature = m_origProjectProps.getTrackChangesSignature();
        if (signature != null) {
            m_trackChangesSignature.setText(signature);
        }
        m_trackChangesSignatureSelection.pack();
        if (m_isTrackingActivatedButton != null) {
            UIComponentHelper.setEnabledRecursive(m_trackChangesSignatureSelection,
                    m_isTrackingActivatedButton.getSelection());
        }
        parent.pack();
    }

    /**
     * @param parent The parent <code>Composite</code>
     */
    private void createTrackChangesDeleteDataButton(Composite parent) {
        m_deleteChanges = new Button(parent, SWT.PUSH);
        m_deleteChanges.setText(Messages.PrefPageTrackChangesDeleteData);
        GridData gridData = new GridData(SWT.END, SWT.BEGINNING, false, false);
        gridData.horizontalSpan = 1;
        gridData.grabExcessHorizontalSpace = false;
        m_deleteChanges.setLayoutData(gridData);

        m_deleteChanges.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                Dialog qDialog = new MessageDialog(getShell(), Messages.UtilsConfirmation, null,
                        Messages.PrefPageTrackChangesDeleteDataQuestion, MessageDialog.QUESTION,
                        new String[] { Messages.UtilsYes, Messages.UtilsNo }, 0);
                qDialog.setBlockOnOpen(true);
                qDialog.open();
                if (qDialog.getReturnCode() == 0) {
                    // delete all tracked changes
                    try {
                        PlatformUI.getWorkbench().getProgressService().run(true, false,
                                new DeleteTrackedChangesOperation());
                    } catch (InvocationTargetException ite) {
                        // nothing
                    } catch (InterruptedException ie) {
                        // nothing
                    }
                }
            }
        });
    }

    /**
     * Checks if Preference Page is complete and valid
     */
    protected void checkCompleteness() {
        if (m_cleanResultDays.isEnabled() && m_cleanResultDays.getValue() <= 0) {
            setErrorMessage(Messages.TestResultViewPreferencePageCleanResultDaysEmpty);
            setValid(false);
            return;
        }
        if (m_trackChangesTimespanSelection.isEnabled()) {
            boolean unitSelected = false;
            for (Control child : m_trackChangesUnitSelection.getChildren()) {
                if (child instanceof Button) {
                    Button bt = (Button) child;
                    if (bt.getSelection()) {
                        unitSelected = true;
                    }
                }
            }
            if (!unitSelected) {
                setErrorMessage(Messages.PrefPageTrackChangesNoUnitSelected);
                setValid(false);
                return;
            }
        }
        if (m_trackChangesTimespanSelection.isEnabled() && m_trackChangesSpan.getValue() <= 0) {
            setErrorMessage(Messages.PrefPageTrackChangesTimespanEmpty);
            setValid(false);
            return;
        }
        final String trackChangesSignature = m_trackChangesSignature.getText();
        if (m_trackChangesTimespanSelection.isEnabled() && !StringUtils.isEmpty(trackChangesSignature)
                && EnvironmentUtils.getProcessOrSystemProperty(trackChangesSignature) == null) {
            setErrorMessage(Messages.PrefPageTrackChangesSignatureInvalid);
            setValid(false);
            return;
        }
        setErrorMessage(null);
        setValid(true);
    }

    /**
     * {@inheritDoc}
     */
    public boolean performOk() {
        try {
            Plugin.startLongRunning(Messages.RefreshTSBrowserActionProgressMessage);
            if (!m_oldProjectName.equals(m_newProjectName)) {
                if (ProjectPM.doesProjectNameExist(m_newProjectName)) {

                    ErrorHandlingUtil.createMessageDialog(MessageIDs.E_PROJECTNAME_ALREADY_EXISTS,
                            new Object[] { m_newProjectName }, null);
                    return false;
                }
            }
            IProjectPO project = getProject();
            storeProperties();
            storeAutoTestResultCleanup();
            if (!m_oldProjectName.equals(m_newProjectName)) {
                ProjectNameBP.getInstance().setName(getEditSupport().getSession(), project.getGuid(),
                        m_newProjectName);
            }
            fireOkPressed();
            Set<IReusedProjectPO> origReused = ((IProjectPropertiesPO) getEditSupport().getOriginal())
                    .getUsedProjects();
            Set<IReusedProjectPO> newReused = new HashSet<IReusedProjectPO>(
                    ((IProjectPropertiesPO) getEditSupport().getWorkVersion()).getUsedProjects());
            boolean needRefresh = !origReused.containsAll(newReused) || !newReused.containsAll(origReused);
            newReused.removeAll(origReused);
            getEditSupport().saveWorkVersion();
            refreshAutMainList();
            boolean doSearchQuery = false;
            doSearchQuery = handleReusedChanged(newReused, needRefresh);
            DataEventDispatcher ded = DataEventDispatcher.getInstance();
            ded.fireProjectStateChanged(ProjectState.prop_modified);

            List<DataChangedEvent> events = new ArrayList<DataChangedEvent>();
            // FIXME zeb This updates the Test Case Browser. Once we have separate
            //           EditSupports for each property page, then we can use 
            //           "real" ReusedProjectPOs instead of a placeholder.
            events.add(new DataChangedEvent(PoMaker.createReusedProjectPO("1", 1, 1, null, null), //$NON-NLS-1$
                    DataState.ReuseChanged, UpdateState.notInEditor));
            events.add(new DataChangedEvent(GeneralStorage.getInstance().getProject(), DataState.Renamed,
                    UpdateState.notInEditor));
            ded.fireDataChangedListener(events.toArray(new DataChangedEvent[0]));
            CompletenessBP.getInstance().completeProjectCheck();
            if (doSearchQuery) {
                NewSearchUI.runQueryInBackground(new DeprecatedModulesQuery());
            }

        } catch (PMException e) {
            ErrorHandlingUtil.createMessageDialog(e, null, null);
        } catch (ProjectDeletedException e) {
            PMExceptionHandler.handleProjectDeletedException();
        } catch (InterruptedException e) {
            ErrorHandlingUtil.createMessageDialog(
                    new JBException(Messages.UnexpectedError, e, MessageIDs.E_UNEXPECTED_EXCEPTION));
        } catch (InvocationTargetException e) {
            ErrorHandlingUtil.createMessageDialog(
                    new JBException(Messages.UnexpectedError, e, MessageIDs.E_UNEXPECTED_EXCEPTION));
        }
        Plugin.stopLongRunning();
        return true;
    }

    /**
     * this method asks if it should be searched for used deprecated
     * modules {@link DeprecatedModulesQuery} and also refreshes the master
     * session if there was a change in the reused of projects.
     * @param newReused the list of new {@link IReusedProjectPO}
     * @param needRefresh whether a refresh of the project is needed
     * @return boolean which states if the search query should be done
     * @throws InvocationTargetException might occur during refresh
     * @throws InterruptedException might occur during refresh
     */
    private boolean handleReusedChanged(Set<IReusedProjectPO> newReused, boolean needRefresh)
            throws InvocationTargetException, InterruptedException {
        boolean doSearchQuery = false;
        if (!newReused.isEmpty()) {
            doSearchQuery = openSearchForDeprecatedDialog();
        }
        if (needRefresh) {
            PlatformUI.getWorkbench().getProgressService().run(false, false,
                    new RefreshProjectHandler.RefreshProjectOperation());
        }
        for (IReusedProjectPO reused : newReused) {
            try {
                IProjectPO reusedProject = ProjectPM.loadReusedProject(reused);
            } catch (JBException e) {
                // Could not refresh Component Name information for
                // reused project. Log the exception.
                log.error(Messages.ErrorWhileRetrievingReusedProjectInformation, e);
            }
        }
        return doSearchQuery;
    }

    /**
     * creates and opens a dialog if a search for the deprecated Modules
     * should be done
     * @return the boolean if the search should be done
     */
    private boolean openSearchForDeprecatedDialog() {
        MessageDialog mdiag = new MessageDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
                Messages.ProjectPropertyPageSearchForDeprProjModuleTitle, null,
                Messages.ProjectPropertyPageSearchForDeprProjModuleMsg, MessageDialog.QUESTION,
                new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 0);
        mdiag.create();
        Plugin.getHelpSystem().setHelp(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
                ContextHelpIds.SEARCH_FOR_DEPRECATED_MODULES_DIALOG);
        return (mdiag.open() == Window.OK);
    }

    /**
     * store properties into the database
     */
    private void storeProperties() {
        IProjectPO project = getProject();
        if (m_isReusableCheckbox != null) {
            project.setIsReusable(m_isReusableCheckbox.getSelection());
        }
        if (m_isProtectedCheckbox != null) {
            project.setIsProtected(m_isProtectedCheckbox.getSelection());
        }
        if (m_projectDescriptionTextField != null) {
            project.setComment(m_projectDescriptionTextField.getText());
        }
        if (m_isTrackingActivatedButton != null) {
            project.setIsTrackingActivated(m_isTrackingActivatedButton.getSelection());
        }
        if (m_trackChangesSignature != null) {
            project.getProjectProperties().setTrackChangesSignature(m_trackChangesSignature.getText());
        }
        if (m_trackChangesSpan != null && m_trackChangesSpan.getText() != null
                && !m_trackChangesSpan.getText().equals("")) { //$NON-NLS-1$
            project.getProjectProperties().setTrackChangesSpan(Integer.valueOf(m_trackChangesSpan.getText()));
        }
        if (m_trackChangesUnitSelection != null) {
            TrackingUnit unit = null;
            for (Control child : m_trackChangesUnitSelection.getChildren()) {
                if (child instanceof Button) {
                    Button bt = (Button) child;
                    if (bt.getSelection()) {
                        String btText = bt.getText();
                        if (btText.equals("Days")) { //$NON-NLS-1$
                            unit = TrackingUnit.DAYS;
                        } else if (btText.equals("Changes")) { //$NON-NLS-1$
                            unit = TrackingUnit.CHANGES;
                        }
                    }
                }
            }
            if (unit != null) {
                project.getProjectProperties().setTrackChangesUnit(unit);
            }
        }
    }

    /**
     * store preferences made for auto test result cleanup
     */
    private void storeAutoTestResultCleanup() {
        if (m_cleanResultDays != null) {
            if (m_cleanTestresults != null) {
                boolean autoClean = m_cleanTestresults.getSelection();
                if (autoClean) {
                    getProject().setTestResultCleanupInterval(Integer.valueOf(m_cleanResultDays.getText()));
                } else {
                    getProject().setTestResultCleanupInterval(IProjectPO.NO_CLEANUP);
                }
            }
        }
    }

    /**
     * Notify listeners that OK was pressed.
     */
    private void fireOkPressed() throws PMException {
        for (IOkListener listener : m_okListenerList) {
            listener.okPressed();
        }
    }

    /**
     * Refreshes the AutMainList of the Project.
     */
    private void refreshAutMainList() throws ProjectDeletedException {
        try {
            GeneralStorage.getInstance().getMasterSession()
                    .refresh(GeneralStorage.getInstance().getProject().getAutCont());
        } catch (EntityNotFoundException enfe) {
            // Occurs if any Object Mapping information has been deleted while
            // the Project Properties were being edited.
            // Refresh the entire master session to ensure that AUT settings
            // and Object Mappings are in sync
            GeneralStorage.getInstance().reloadMasterSession(new NullProgressMonitor());
        }
    }

    /**
     * Adds necessary listeners.
     */
    private void addListener() {
        m_projectNameTextField.addModifyListener(m_modifyListener);
        m_projectToolkitCombo.addSelectionListener(m_toolkitComboListener);
        m_projectMarkupCombo.addSelectionListener(m_markupComboListener);
    }

    /** 
     * The action of the project name field.
     * @param isProjectNameVerified True, if the project name was verified.
     * @return false, if the project name field contents an error:
     * the project name starts or end with a blank, or the field is empty
     */
    boolean modifyProjectNameFieldAction(boolean isProjectNameVerified) {

        boolean isCorrect = true;
        String projectName = m_projectNameTextField.getText();
        int projectNameLength = projectName.length();
        super.getShell().setText(Messages.ProjectPropertyPageShellTitle + projectName);
        if ((projectNameLength == 0) || (projectName.startsWith(StringConstants.SPACE))
                || (projectName.charAt(projectNameLength - 1) == ' ')) {

            isCorrect = false;
        }
        if (isCorrect) {
            setErrorMessage(null);
            setMessage(Messages.PropertiesActionPage1, NONE);
            setValid(true);
            if (isProjectNameVerified) {
                m_newProjectName = projectName;
            }
            if (ProjectPM.doesProjectNameExist(projectName) && !m_oldProjectName.equals(projectName)) {

                setErrorMessage(Messages.ProjectSettingWizardPageDoubleProjectName);
                isCorrect = false;
                setValid(false);
            }
        } else {
            if (projectNameLength == 0) {
                setErrorMessage(Messages.ProjectWizardEmptyProject);
                setValid(false);
            } else {
                setErrorMessage(Messages.ProjectWizardNotValidProject);
                setValid(false);
            }
        }
        return isCorrect;
    }

    /**
     * This private inner class contains a new ModifyListener.
     * @author BREDEX GmbH
     * @created 11.07.2005
     */
    @SuppressWarnings("synthetic-access")
    private class WidgetModifyListener implements ModifyListener {
        /**
         * {@inheritDoc}
         */
        public void modifyText(ModifyEvent e) {
            Object o = e.getSource();
            if (o.equals(m_projectNameTextField)) {
                modifyProjectNameFieldAction(true);
                return;
            }
        }
    }

    /**
     * @author BREDEX GmbH
     */
    private class MarkupComboSelectionListener implements SelectionListener {

        /** {@inheritDoc} */
        public void widgetSelected(SelectionEvent e) {
            Object o = e.getSource();
            if (o.equals(m_projectMarkupCombo)) {
                handleMarkupSelection();
                return;
            }
            Assert.notReached(Messages.EventActivatedUnknownWidget + StringConstants.DOT);
        }

        /**
         * handles the selection of the markupLanguageCombo
         */
        private void handleMarkupSelection() {
            final String newMarkup = m_projectMarkupCombo.getSelectedObject();
            final IProjectPO project = getProject();
            project.setMarkupLanguage(newMarkup);
        }

        /** {@inheritDoc} */
        public void widgetDefaultSelected(SelectionEvent e) {
            Assert.notReached(Messages.EventActivatedUnknownWidget + StringConstants.DOT);
        }
    }

    /**
     * This private inner class contains a new SelectionListener.
     * @author BREDEX GmbH
     * @created 10.02.2005
     */
    @SuppressWarnings("synthetic-access")
    private class ToolkitComboSelectionListener implements SelectionListener {

        /**
         * {@inheritDoc}
         */
        public void widgetSelected(SelectionEvent e) {
            Object o = e.getSource();
            if (o.equals(m_projectToolkitCombo)) {
                handleAutToolkitSelection();
                return;
            }
            Assert.notReached(Messages.EventActivatedUnknownWidget + StringConstants.DOT);
        }

        /**
         * Handles the selection of the autToolkitCombo
         */
        private void handleAutToolkitSelection() {
            final String newToolkit = m_projectToolkitCombo.getSelectedObject();
            final IProjectPO project = getProject();
            project.setToolkit(newToolkit);
        }

        /**
         * {@inheritDoc}
         */
        public void widgetDefaultSelected(SelectionEvent e) {
            Assert.notReached(Messages.EventActivatedUnknownWidget + StringConstants.DOT);
        }
    }

    /**
     * @param toAdd The listener to add. 
     */
    public void addOkListener(IOkListener toAdd) {
        m_okListenerList.add(toAdd);
    }

    /**
     * {@inheritDoc}
     */
    public void setVisible(boolean visible) {
        refreshAutToolkitCombo();
        super.setVisible(visible);
    }

    /**
     * Refreshes the m_autToolkitCombo.
     */
    private void refreshAutToolkitCombo() {
        final Composite parent = m_projectToolkitCombo.getParent();
        final DirectCombo<String> tmpCombo = ControlFactory.createProjectToolkitCombo(parent);
        m_projectToolkitCombo.setItems(tmpCombo.getValues(), Arrays.asList(tmpCombo.getItems()));
        tmpCombo.dispose();
        m_projectToolkitCombo.setSelectedObject(getProject().getToolkit());
    }

    /**
     * Operation for deleting tracked changes
     * 
     * @author BREDEX GmbH
     */
    private class DeleteTrackedChangesOperation implements IRunnableWithProgress {

        /**
         * {@inheritDoc}
         */
        public void run(IProgressMonitor monitor) {
            final IProjectPO project = GeneralStorage.getInstance().getProject();
            final Map<INodePO, Boolean> nodeToWasLockedMap;
            try {
                nodeToWasLockedMap = NodePM.cleanupTrackedChanges(monitor, project);

                List<INodePO> listOfLockedNodes = new ArrayList<>(nodeToWasLockedMap.size());
                for (INodePO node : nodeToWasLockedMap.keySet()) {
                    if (nodeToWasLockedMap.get(node).booleanValue()) {
                        listOfLockedNodes.add(node);
                    }
                }

                Display d = Plugin.getDisplay();
                if (d != null && !d.isDisposed()) {
                    fireDataChangedListeners(d, nodeToWasLockedMap);
                }

                if (!listOfLockedNodes.isEmpty()) {
                    Object[] details = listOfLockedNodes.toArray();
                    String[] namesOfLockedNodes;
                    final int maxNumberOfLockedNodesToDisplay = 10;

                    if (details.length <= maxNumberOfLockedNodesToDisplay) {
                        // not too many locked nodes to display them all
                        namesOfLockedNodes = new String[details.length];
                        for (int i = 0; i < namesOfLockedNodes.length; i++) {
                            namesOfLockedNodes[i] = ((INodePO) details[i]).getName();
                        }
                        ErrorHandlingUtil.createMessageDialog(MessageIDs.I_COULD_NOT_DELETE_ALL_TRACKED_CHANGES,
                                null, namesOfLockedNodes);
                    } else {
                        // too many locked nodes to display them all
                        namesOfLockedNodes = new String[maxNumberOfLockedNodesToDisplay];
                        for (int i = 0; i < namesOfLockedNodes.length; i++) {
                            namesOfLockedNodes[i] = ((INodePO) details[i]).getName();
                        }
                        Object[] params = new Object[2];
                        params[0] = maxNumberOfLockedNodesToDisplay;
                        params[1] = details.length;
                        ErrorHandlingUtil.createMessageDialog(
                                MessageIDs.I_COULD_NOT_DELETE_ALL_TRACKED_CHANGES_MANY, params, namesOfLockedNodes);
                    }
                }
            } catch (PMException e) {
                ErrorHandlingUtil.createMessageDialog(e);
            } catch (ProjectDeletedException e) {
                ErrorHandlingUtil.createMessageDialog(e);
            }
        }
    }

    /**
     * Fires data state listeners for those nodes which were not locked
     * @param d the active Display
     * @param nodeToWasLockedMap the map indicating which nodes were locked
     */
    private void fireDataChangedListeners(Display d, final Map<INodePO, Boolean> nodeToWasLockedMap) {
        d.syncExec(new Runnable() {
            public void run() {
                for (INodePO node : nodeToWasLockedMap.keySet()) {
                    if (!nodeToWasLockedMap.get(node).booleanValue()) {
                        DataEventDispatcher.getInstance().fireDataChangedListener(node, DataState.StructureModified,
                                UpdateState.all);
                    }
                }
            }
        });
    }
}