org.eclipse.mylyn.internal.bugzilla.ui.search.BugzillaSearchPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.mylyn.internal.bugzilla.ui.search.BugzillaSearchPage.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2010 Tasktop Technologies and others.
 * 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:
 *     Tasktop Technologies - initial API and implementation
 *     Frank Becker - improvements
 *******************************************************************************/

package org.eclipse.mylyn.internal.bugzilla.ui.search;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.fieldassist.ComboContentAdapter;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.mylyn.commons.ui.dialogs.AbstractInPlaceDialog;
import org.eclipse.mylyn.commons.ui.dialogs.IInPlaceDialogListener;
import org.eclipse.mylyn.commons.ui.dialogs.InPlaceDialogEvent;
import org.eclipse.mylyn.commons.workbench.InPlaceCheckBoxTreeDialog;
import org.eclipse.mylyn.commons.workbench.WorkbenchUtil;
import org.eclipse.mylyn.commons.workbench.forms.SectionComposite;
import org.eclipse.mylyn.internal.bugzilla.core.BugzillaAttribute;
import org.eclipse.mylyn.internal.bugzilla.core.BugzillaCustomField;
import org.eclipse.mylyn.internal.bugzilla.core.BugzillaRepositoryConnector;
import org.eclipse.mylyn.internal.bugzilla.core.BugzillaSearch;
import org.eclipse.mylyn.internal.bugzilla.core.BugzillaSearch.Entry;
import org.eclipse.mylyn.internal.bugzilla.core.IBugzillaConstants;
import org.eclipse.mylyn.internal.bugzilla.core.RepositoryConfiguration;
import org.eclipse.mylyn.internal.bugzilla.ui.BugzillaUiPlugin;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.TasksUi;
import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage2;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
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.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.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;

/**
 * Bugzilla search page
 * 
 * @author Mik Kersten (hardening of prototype)
 * @author Frank Becker
 */
public class BugzillaSearchPage extends AbstractRepositoryQueryPage2 implements Listener {

    private static final int HEIGHT_ATTRIBUTE_COMBO = 30;

    private static ArrayList<BugzillaSearchData> previousSummaryPatterns = new ArrayList<BugzillaSearchData>(20);

    private static ArrayList<BugzillaSearchData> previousEmailPatterns = new ArrayList<BugzillaSearchData>(20);

    private static ArrayList<BugzillaSearchData> previousEmailPatterns2 = new ArrayList<BugzillaSearchData>(20);

    private static ArrayList<BugzillaSearchData> previousCommentPatterns = new ArrayList<BugzillaSearchData>(20);

    private static ArrayList<BugzillaSearchData> previousKeywords = new ArrayList<BugzillaSearchData>(20);

    private static ArrayList<BugzillaSearchData> previousWhiteboardPatterns = new ArrayList<BugzillaSearchData>(20);

    private boolean firstTime = true;

    private IDialogSettings fDialogSettings;

    private static final String[] patternOperationText = { Messages.BugzillaSearchPage_OperationText_allwordssubstr,
            Messages.BugzillaSearchPage_OperationText_anywordssubstr,
            Messages.BugzillaSearchPage_OperationText_substring,
            Messages.BugzillaSearchPage_OperationText_casesubstring,
            Messages.BugzillaSearchPage_OperationText_allwords, Messages.BugzillaSearchPage_OperationText_anywords,
            Messages.BugzillaSearchPage_OperationText_regexp, Messages.BugzillaSearchPage_OperationText_notregexp };

    private static final String[] patternOperationValues = { "allwordssubstr", "anywordssubstr", "substring", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
            "casesubstring", "allwords", "anywords", "regexp", "notregexp" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$

    private static final String[] emailOperationText = { Messages.BugzillaSearchPage_EmailOperation_substring,
            Messages.BugzillaSearchPage_EmailOperation_exact, Messages.BugzillaSearchPage_EmailOperation_notequals,
            Messages.BugzillaSearchPage_EmailOperation_regexp,
            Messages.BugzillaSearchPage_EmailOperation_notregexp };

    private static final String[] emailOperationValues = { "substring", "exact", "notequals", "regexp", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
            "notregexp" }; //$NON-NLS-1$

    private static final String[] keywordOperationText = { Messages.BugzillaSearchPage_all,
            Messages.BugzillaSearchPage_any, Messages.BugzillaSearchPage_none };

    private static final String[] keywordOperationValues = { "allwords", "anywords", "nowords" }; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$

    private static final String[] emailRoleValues = { "emailassigned_to1", "emailreporter1", "emailcc1", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 
            "emaillongdesc1", "emailqa_contact1" }; //$NON-NLS-1$ //$NON-NLS-2$

    private static final String[] emailRoleValues2 = { "emailassigned_to2", "emailreporter2", "emailcc2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 
            "emaillongdesc2", "emailqa_contact2" }; //$NON-NLS-1$ //$NON-NLS-2$

    private static final ArrayList<String> chartFieldTextDefault = new ArrayList<String>() {
        private static final long serialVersionUID = 1974092160992399001L;
        {
            add(Messages.BugzillaSearchPage_Field_Noop);
            add(Messages.BugzillaSearchPage_Field_Alias);
            add(Messages.BugzillaSearchPage_Field_AssignedTo);
            add(Messages.BugzillaSearchPage_Field_Attachment_creator);
            add(Messages.BugzillaSearchPage_Field_Attachment_data);
            add(Messages.BugzillaSearchPage_Field_Attachment_description);
            add(Messages.BugzillaSearchPage_Field_Attachment_filename);
            add(Messages.BugzillaSearchPage_Field_Attachment_is_a_URL);
            add(Messages.BugzillaSearchPage_Field_Attachment_is_obsolete);
            add(Messages.BugzillaSearchPage_Field_Attachment_is_patch);
            add(Messages.BugzillaSearchPage_Field_Attachment_is_private);
            add(Messages.BugzillaSearchPage_Field_Attachment_mime_type);
            add(Messages.BugzillaSearchPage_Field_Blocks);
            add(Messages.BugzillaSearchPage_Field_Bug);
            add(Messages.BugzillaSearchPage_Field_CC);
            add(Messages.BugzillaSearchPage_Field_CC_Accessible);
            add(Messages.BugzillaSearchPage_Field_Classification);
            add(Messages.BugzillaSearchPage_Field_Comment);
            add(Messages.BugzillaSearchPage_Field_Comment_is_private);
            add(Messages.BugzillaSearchPage_Field_Commenter);
            add(Messages.BugzillaSearchPage_Field_Component);
            add(Messages.BugzillaSearchPage_Field_Content);
            add(Messages.BugzillaSearchPage_Field_Creation_date);
            add(Messages.BugzillaSearchPage_Field_Days_since_bug_changed);
            add(Messages.BugzillaSearchPage_Field_Depends_on);
            add(Messages.BugzillaSearchPage_Field_drop_down_custom_field);
            add(Messages.BugzillaSearchPage_Field_Ever_Confirmed);
            add(Messages.BugzillaSearchPage_Field_Flag);
            add(Messages.BugzillaSearchPage_Field_Flag_Requestee);
            add(Messages.BugzillaSearchPage_Field_Flag_Setter);
            add(Messages.BugzillaSearchPage_Field_free_text_custom_field);
            add(Messages.BugzillaSearchPage_Field_Group);
            add(Messages.BugzillaSearchPage_Field_Keywords);
            add(Messages.BugzillaSearchPage_Field_Last_changed_date);
            add(Messages.BugzillaSearchPage_Field_OS_Version);
            add(Messages.BugzillaSearchPage_Field_Platform);
            add(Messages.BugzillaSearchPage_Field_Priority);
            add(Messages.BugzillaSearchPage_Field_Product);
            add(Messages.BugzillaSearchPage_Field_QAContact);
            add(Messages.BugzillaSearchPage_Field_ReportedBy);
            add(Messages.BugzillaSearchPage_Field_Reporter_Accessible);
            add(Messages.BugzillaSearchPage_Field_Resolution);
            add(Messages.BugzillaSearchPage_Field_Severity);
            add(Messages.BugzillaSearchPage_Field_Status);
            add(Messages.BugzillaSearchPage_Field_Status_Whiteboard);
            add(Messages.BugzillaSearchPage_Field_Summary);
            add(Messages.BugzillaSearchPage_Field_Target_Milestone);
            add(Messages.BugzillaSearchPage_Field_Time_Since_Assignee_Touched);
            add(Messages.BugzillaSearchPage_Field_URL);
            add(Messages.BugzillaSearchPage_Field_Version);
            add(Messages.BugzillaSearchPage_Field_Votes);
        }
    };

    private static final ArrayList<String> chartFieldValuesDefault = new ArrayList<String>() {
        private static final long serialVersionUID = 9135403539678279982L;
        {
            add("noop"); //$NON-NLS-1$
            add("alias"); //$NON-NLS-1$
            add("assigned_to"); //$NON-NLS-1$
            add("attachments.submitter"); //$NON-NLS-1$
            add("attach_data.thedata"); //$NON-NLS-1$
            add("attachments.description"); //$NON-NLS-1$
            add("attachments.filename"); //$NON-NLS-1$
            add("attachments.isurl"); //$NON-NLS-1$
            add("attachments.isobsolete"); //$NON-NLS-1$
            add("attachments.ispatch"); //$NON-NLS-1$
            add("attachments.isprivate"); //$NON-NLS-1$
            add("attachments.mimetype"); //$NON-NLS-1$
            add("blocked"); //$NON-NLS-1$
            add("bug_id"); //$NON-NLS-1$
            add("cc"); //$NON-NLS-1$
            add("cclist_accessible"); //$NON-NLS-1$
            add("classification"); //$NON-NLS-1$
            add("longdesc"); //$NON-NLS-1$
            add("longdescs.isprivate"); //$NON-NLS-1$
            add("commenter"); //$NON-NLS-1$
            add("component"); //$NON-NLS-1$
            add("content"); //$NON-NLS-1$
            add("creation_ts"); //$NON-NLS-1$
            add("days_elapsed"); //$NON-NLS-1$
            add("dependson"); //$NON-NLS-1$
            add("cf_dropdown"); //$NON-NLS-1$
            add("everconfirmed"); //$NON-NLS-1$
            add("flagtypes.name"); //$NON-NLS-1$
            add("requestees.login_name"); //$NON-NLS-1$
            add("setters.login_name"); //$NON-NLS-1$
            add("cf_freetext"); //$NON-NLS-1$
            add("bug_group"); //$NON-NLS-1$
            add("keywords"); //$NON-NLS-1$
            add("delta_ts"); //$NON-NLS-1$
            add("op_sys"); //$NON-NLS-1$
            add("rep_platform"); //$NON-NLS-1$
            add("priority"); //$NON-NLS-1$
            add("product"); //$NON-NLS-1$
            add("qa_contact"); //$NON-NLS-1$
            add("reporter"); //$NON-NLS-1$
            add("reporter_accessible"); //$NON-NLS-1$
            add("resolution"); //$NON-NLS-1$
            add("bug_severity"); //$NON-NLS-1$
            add("bug_status"); //$NON-NLS-1$
            add("status_whiteboard"); //$NON-NLS-1$
            add("short_desc"); //$NON-NLS-1$
            add("target_milestone"); //$NON-NLS-1$
            add("owner_idle_time"); //$NON-NLS-1$
            add("bug_file_loc"); //$NON-NLS-1$
            add("version"); //$NON-NLS-1$
            add("votes"); //$NON-NLS-1$
        }
    };

    private static final String[] chartOperationText = { Messages.BugzillaSearchPage_Operation_Noop,
            Messages.BugzillaSearchPage_Operation_is_equal_to,
            Messages.BugzillaSearchPage_Operation_is_not_equal_to,
            Messages.BugzillaSearchPage_Operation_is_equal_to_any_of_the_strings,
            Messages.BugzillaSearchPage_Operation_contains_the_string,
            Messages.BugzillaSearchPage_Operation_contains_the_string_exact_case,
            Messages.BugzillaSearchPage_Operation_does_not_contain_the_string,
            Messages.BugzillaSearchPage_Operation_contains_any_of_the_strings,
            Messages.BugzillaSearchPage_Operation_contains_all_of_the_strings,
            Messages.BugzillaSearchPage_Operation_contains_none_of_the_strings,
            Messages.BugzillaSearchPage_Operation_contains_regexp,
            Messages.BugzillaSearchPage_Operation_does_not_contain_regexp,
            Messages.BugzillaSearchPage_Operation_is_less_than,
            Messages.BugzillaSearchPage_Operation_is_greater_than,
            Messages.BugzillaSearchPage_Operation_contains_any_of_he_words,
            Messages.BugzillaSearchPage_Operation_contains_all_of_the_words,
            Messages.BugzillaSearchPage_Operation_contains_none_of_the_words,
            Messages.BugzillaSearchPage_Operation_changed_before,
            Messages.BugzillaSearchPage_Operation_changed_after, Messages.BugzillaSearchPage_Operation_changed_from,
            Messages.BugzillaSearchPage_Operation_changed_to, Messages.BugzillaSearchPage_Operation_changed_by,
            Messages.BugzillaSearchPage_Operation_matches };

    private static final String[] chartOperationValues = { "noop", "equals", "notequals", "anyexact", "substring", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
            "casesubstring", "notsubstring", "anywordssubstr", "allwordssubstr", "nowordssubstr", "regexp", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
            "notregexp", "lessthan", "greaterthan", "anywords", "allwords", "nowords", "changedbefore", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$//$NON-NLS-7$
            "changedafter", //$NON-NLS-1$
            "changedfrom", "changedto", "changedby", "matches" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$

    private final static String REGEXP_CHART_EXPR = "(field|type|value)([0-9]+)-([0-9]+)-([0-9]+)"; //$NON-NLS-1$

    private static final Pattern PATTERN_CHART_EXPR = Pattern.compile(REGEXP_CHART_EXPR, Pattern.CASE_INSENSITIVE);

    private final static String REGEXP_CHART_NEGATE = "(negate)([0-9]+)"; //$NON-NLS-1$

    private static final Pattern PATTERN_CHART_NEGATE = Pattern.compile(REGEXP_CHART_NEGATE,
            Pattern.CASE_INSENSITIVE);

    private IRepositoryQuery originalQuery = null;

    protected boolean restoring = false;

    private boolean restoreQueryOptions = true;

    protected Combo summaryPattern;

    protected Combo summaryOperation;

    protected List product;

    protected List os;

    protected List hardware;

    protected List priority;

    protected List severity;

    protected List resolution;

    protected List status;

    protected Combo commentOperation;

    protected Combo commentPattern;

    protected List component;

    protected List version;

    protected List target;

    protected Combo emailOperation;

    protected Combo emailOperation2;

    protected Combo emailPattern;

    protected Combo emailPattern2;

    protected Button[] emailButtons;

    protected Button[] emailButtons2;

    private Combo keywords;

    private Combo keywordsOperation;

    protected Combo whiteboardPattern;

    private Combo whiteboardOperation;

    protected Text daysText;

    protected String[] chartFieldText;

    protected String[] chartFieldValues;

    /** Index of the saved query to run */
    protected int selIndex;

    // Dialog store taskId constants
    protected final static String PAGE_NAME = "BugzillaSearchPage"; //$NON-NLS-1$

    private final FormToolkit toolkit;

    private ExpandableComposite moreOptionsSection;

    private ExpandableComposite chartSection;

    private SectionComposite scrolledComposite;

    private final ArrayList<Chart> charts = new ArrayList<Chart>(1);

    private final ArrayList<ControlDecoration> errorDecorations = new ArrayList<ControlDecoration>();

    private class ChartControls {
        private final Combo field;

        private final Combo operation;

        private final Combo value;

        public ChartControls(Combo field, Combo operation, Combo value) {
            super();
            this.field = field;
            this.operation = operation;
            this.value = value;
        }

        public Combo getField() {
            return field;
        }

        public Combo getOperation() {
            return operation;
        }

        public Combo getValue() {
            return value;
        }
    }

    private final ArrayList<ArrayList<ArrayList<ChartControls>>> chartControls = new ArrayList<ArrayList<ArrayList<ChartControls>>>();

    private final ArrayList<Button> negateButtons = new ArrayList<Button>();

    private final SelectionAdapter updateActionSelectionAdapter = new SelectionAdapter() {
        @Override
        public void widgetSelected(SelectionEvent e) {
            if (isControlCreated()) {
                setPageComplete(isPageComplete());
            }
        }
    };

    private final class ModifyListenerImplementation implements ModifyListener {
        public void modifyText(ModifyEvent e) {
            if (isControlCreated()) {
                setPageComplete(isPageComplete());
            }
        }
    }

    @Override
    public void setPageComplete(boolean complete) {
        super.setPageComplete(complete);
        if (getSearchContainer() != null) {
            getSearchContainer().setPerformActionEnabled(complete);
        }
    }

    private static class BugzillaSearchData {
        /** Pattern to match on */
        String pattern;

        /** Pattern matching criterion */
        int operation;

        BugzillaSearchData(String pattern, int operation) {
            this.pattern = pattern;
            this.operation = operation;
        }
    }

    @Override
    protected void createButtons(Composite control) {
        if (originalQuery != null) {
            return;
        }
        super.createButtons(control);
    }

    @Override
    public void doClearControls() {
        product.deselectAll();
        component.deselectAll();
        version.deselectAll();
        target.deselectAll();
        status.deselectAll();
        resolution.deselectAll();
        severity.deselectAll();
        priority.deselectAll();
        hardware.deselectAll();
        os.deselectAll();
        summaryOperation.select(0);
        commentOperation.select(0);
        emailOperation.select(1);

        for (Button emailButton : emailButtons) {
            emailButton.setSelection(false);
        }
        summaryPattern.setText(""); //$NON-NLS-1$
        commentPattern.setText(""); //$NON-NLS-1$
        emailPattern.setText(""); //$NON-NLS-1$
        emailOperation2.select(1);
        for (Button element : emailButtons2) {
            element.setSelection(false);
        }
        emailPattern2.setText(""); //$NON-NLS-1$
        keywords.setText(""); //$NON-NLS-1$
        keywordsOperation.select(0);
        whiteboardPattern.setText(""); //$NON-NLS-1$
        whiteboardOperation.select(0);
        daysText.setText(""); //$NON-NLS-1$

        charts.clear();
        charts.add(0, new Chart());
        recreateChartControls();
    }

    @Override
    protected void createPageContent(SectionComposite parent) {
        this.scrolledComposite = parent;

        Composite scrolledBodyComposite = scrolledComposite.getContent();
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        layout.horizontalSpacing = 0;
        layout.verticalSpacing = 0;
        scrolledBodyComposite.setLayout(layout);

        basicCompositeCreate(scrolledBodyComposite);
        createMoreOptionsSection(scrolledBodyComposite);
        createChartSection(scrolledBodyComposite);

        Point p = scrolledBodyComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
        scrolledComposite.setMinSize(p);
    }

    private void basicCompositeCreate(Composite parent) {
        final Composite basicComposite = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout(4, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        //layout.marginRight = 5;
        basicComposite.setLayout(layout);
        GridData g = new GridData(GridData.FILL, GridData.FILL, true, true);
        g.widthHint = 500;
        basicComposite.setLayoutData(g);
        Dialog.applyDialogFont(basicComposite);

        // Info text
        Label labelSummary = new Label(basicComposite, SWT.LEFT);
        labelSummary.setText(Messages.BugzillaSearchPage_Summary);

        // Pattern combo
        summaryPattern = new Combo(basicComposite, SWT.SINGLE | SWT.BORDER);
        summaryPattern.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
        summaryPattern.addModifyListener(new ModifyListenerImplementation());
        summaryPattern.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleWidgetSelected(summaryPattern, summaryOperation, previousSummaryPatterns);
            }
        });

        summaryOperation = new Combo(basicComposite, SWT.SINGLE | SWT.READ_ONLY | SWT.BORDER);
        summaryOperation.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        summaryOperation.setItems(patternOperationText);
        summaryOperation.setText(patternOperationText[0]);
        summaryOperation.select(0);
        Label labelEmail = new Label(basicComposite, SWT.LEFT);
        labelEmail.setText(Messages.BugzillaSearchPage_Email);

        // pattern combo
        emailPattern = new Combo(basicComposite, SWT.SINGLE | SWT.BORDER);
        emailPattern.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
        emailPattern.addModifyListener(new ModifyListenerImplementation());
        emailPattern.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleWidgetSelected(emailPattern, emailOperation, previousEmailPatterns);
            }
        });
        IContentProposalProvider proposalProvider = TasksUi.getUiFactory()
                .createPersonContentProposalProvider(getTaskRepository());
        ILabelProvider proposalLabelProvider = TasksUi.getUiFactory()
                .createPersonContentProposalLabelProvider(getTaskRepository());

        ContentAssistCommandAdapter adapter = new ContentAssistCommandAdapter(emailPattern,
                new ComboContentAdapter(), proposalProvider,
                ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, new char[0], true);
        adapter.setLabelProvider(proposalLabelProvider);
        adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);

        // operation combo
        emailOperation = new Combo(basicComposite, SWT.SINGLE | SWT.READ_ONLY | SWT.BORDER);
        emailOperation.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        emailOperation.setItems(emailOperationText);
        emailOperation.setText(emailOperationText[1]);
        emailOperation.select(1);

        new Label(basicComposite, SWT.NONE);
        Composite emailComposite = new Composite(basicComposite, SWT.NONE);
        emailComposite.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
        GridLayout emailLayout = new GridLayout();
        emailLayout.marginWidth = 0;
        emailLayout.marginHeight = 0;
        emailLayout.horizontalSpacing = 2;
        emailLayout.numColumns = 5;
        emailComposite.setLayout(emailLayout);

        Button button0 = new Button(emailComposite, SWT.CHECK);
        button0.setText(Messages.BugzillaSearchPage_owner);

        Button button1 = new Button(emailComposite, SWT.CHECK);
        button1.setText(Messages.BugzillaSearchPage_reporter);

        Button button2 = new Button(emailComposite, SWT.CHECK);
        button2.setText(Messages.BugzillaSearchPage_cc);

        Button button3 = new Button(emailComposite, SWT.CHECK);
        button3.setText(Messages.BugzillaSearchPage_commenter);

        Button button4 = new Button(emailComposite, SWT.CHECK);
        button4.setText(Messages.BugzillaSearchPage_qacontact);
        button0.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(isPageComplete());
            }
        });
        button1.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(isPageComplete());
            }
        });
        button2.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(isPageComplete());
            }
        });
        button3.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(isPageComplete());
            }
        });
        button4.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(isPageComplete());
            }
        });

        emailButtons = new Button[] { button0, button1, button2, button3, button4 };
        new Label(basicComposite, SWT.NONE);
        GridLayout sashFormLayout = new GridLayout();
        sashFormLayout.numColumns = 4;
        sashFormLayout.marginHeight = 5;
        sashFormLayout.marginWidth = 5;
        sashFormLayout.horizontalSpacing = 5;

        SashForm sashForm = new SashForm(basicComposite, SWT.VERTICAL);
        sashForm.setLayout(sashFormLayout);
        final GridData gd_sashForm = new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1);
        gd_sashForm.widthHint = 400;
        gd_sashForm.heightHint = 80;
        sashForm.setLayoutData(gd_sashForm);

        GridLayout topLayout = new GridLayout();
        topLayout.numColumns = 4;
        SashForm topForm = new SashForm(sashForm, SWT.NONE);
        GridData topLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1);
        topLayoutData.widthHint = 00;
        topLayoutData.heightHint = 60;
        topForm.setLayoutData(topLayoutData);
        topForm.setLayout(topLayout);

        GridLayout productLayout = new GridLayout();
        productLayout.marginWidth = 0;
        productLayout.marginHeight = 0;
        productLayout.horizontalSpacing = 0;
        Composite productComposite = new Composite(topForm, SWT.NONE);
        productComposite.setLayout(productLayout);

        Label productLabel = new Label(productComposite, SWT.LEFT);
        productLabel.setText(Messages.BugzillaSearchPage_Product);
        productLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        GridData productLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
        productLayoutData.heightHint = HEIGHT_ATTRIBUTE_COMBO;
        product = new List(productComposite, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
        product.setLayoutData(productLayoutData);
        product.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                updateAttributesBasedOnProductSelection(product.getSelection(), getRepositoryConfiguration());
                setPageComplete(isPageComplete());
            }
        });

        GridLayout componentLayout = new GridLayout();
        componentLayout.marginWidth = 0;
        componentLayout.marginHeight = 0;
        componentLayout.horizontalSpacing = 0;
        Composite componentComposite = new Composite(topForm, SWT.NONE);
        componentComposite.setLayout(componentLayout);

        Label componentLabel = new Label(componentComposite, SWT.LEFT);
        componentLabel.setText(Messages.BugzillaSearchPage_Component);
        componentLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        component = new List(componentComposite, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
        GridData componentLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
        componentLayoutData.heightHint = HEIGHT_ATTRIBUTE_COMBO;
        component.setLayoutData(componentLayoutData);
        component.addSelectionListener(updateActionSelectionAdapter);

        Composite statusComposite = new Composite(topForm, SWT.NONE);
        GridLayout statusLayout = new GridLayout();
        statusLayout.marginWidth = 0;
        statusLayout.horizontalSpacing = 0;
        statusLayout.marginHeight = 0;
        statusComposite.setLayout(statusLayout);

        Label statusLabel = new Label(statusComposite, SWT.LEFT);
        statusLabel.setText(Messages.BugzillaSearchPage_Status);
        statusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        status = new List(statusComposite, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
        final GridData gd_status = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd_status.heightHint = HEIGHT_ATTRIBUTE_COMBO;
        status.setLayoutData(gd_status);
        status.addSelectionListener(updateActionSelectionAdapter);

        Composite severityComposite = new Composite(topForm, SWT.NONE);
        GridLayout severityLayout = new GridLayout();
        severityLayout.marginWidth = 0;
        severityLayout.marginHeight = 0;
        severityLayout.horizontalSpacing = 0;
        severityComposite.setLayout(severityLayout);

        Label severityLabel = new Label(severityComposite, SWT.LEFT);
        severityLabel.setText(Messages.BugzillaSearchPage_Severity);
        severityLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        severity = new List(severityComposite, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
        final GridData gd_severity = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd_severity.heightHint = HEIGHT_ATTRIBUTE_COMBO;
        severity.setLayoutData(gd_severity);
        severity.addSelectionListener(updateActionSelectionAdapter);
    }

    private void createMoreOptionsSection(Composite parent) {
        moreOptionsSection = scrolledComposite.createSection(Messages.BugzillaSearchPage_More_Options,
                ExpandableComposite.COMPACT | ExpandableComposite.TWISTIE | ExpandableComposite.TITLE_BAR, true);
        GridData g = new GridData(GridData.FILL, GridData.CENTER, true, false);
        g.horizontalSpan = 4;
        moreOptionsSection.setLayoutData(g);

        Composite moreOptionsComposite = new Composite(moreOptionsSection, SWT.NONE);
        GridLayout optionsLayout = new GridLayout(4, false);
        optionsLayout.marginHeight = 0;
        optionsLayout.marginWidth = 0;
        moreOptionsComposite.setLayout(optionsLayout);
        moreOptionsSection.setClient(moreOptionsComposite);

        createMoreOptionsContent(moreOptionsComposite);
        createMoreOptionsChangedInFilter(moreOptionsComposite);
    }

    private void createChartSection(Composite parent) {
        chartFieldText = chartFieldTextDefault.toArray(new String[chartFieldTextDefault.size()]);
        chartFieldValues = chartFieldValuesDefault.toArray(new String[chartFieldValuesDefault.size()]);

        chartSection = scrolledComposite.createSection(Messages.BugzillaSearchPage_BooleanChart,
                ExpandableComposite.COMPACT | ExpandableComposite.TWISTIE | ExpandableComposite.TITLE_BAR, false);
        GridData g = new GridData(GridData.FILL, GridData.BEGINNING, true, false);
        g.horizontalSpan = 4;
        chartSection.setLayoutData(g);

        charts.add(0, new Chart());
        recreateChartControls();
    }

    private void createMoreOptionsContent(Composite advancedComposite) {

        // Info text
        Label labelComment = new Label(advancedComposite, SWT.LEFT);
        labelComment.setText(Messages.BugzillaSearchPage_Comment);

        // Comment pattern combo
        commentPattern = new Combo(advancedComposite, SWT.SINGLE | SWT.BORDER);
        commentPattern.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
        commentPattern.addModifyListener(new ModifyListenerImplementation());
        commentPattern.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleWidgetSelected(commentPattern, commentOperation, previousCommentPatterns);
            }
        });

        commentOperation = new Combo(advancedComposite, SWT.SINGLE | SWT.READ_ONLY | SWT.BORDER);
        commentOperation.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        commentOperation.setItems(patternOperationText);
        commentOperation.setText(patternOperationText[0]);
        commentOperation.select(0);

        Label labelEmail2 = new Label(advancedComposite, SWT.LEFT);
        labelEmail2.setText(Messages.BugzillaSearchPage_Email_2);

        // pattern combo
        emailPattern2 = new Combo(advancedComposite, SWT.SINGLE | SWT.BORDER);
        emailPattern2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
        emailPattern2.addModifyListener(new ModifyListenerImplementation());
        emailPattern2.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleWidgetSelected(emailPattern2, emailOperation2, previousEmailPatterns2);
            }
        });
        IContentProposalProvider proposalProvider = TasksUi.getUiFactory()
                .createPersonContentProposalProvider(getTaskRepository());
        ILabelProvider proposalLabelProvider = TasksUi.getUiFactory()
                .createPersonContentProposalLabelProvider(getTaskRepository());
        ContentAssistCommandAdapter adapter2 = new ContentAssistCommandAdapter(emailPattern2,
                new ComboContentAdapter(), proposalProvider,
                ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, new char[0], true);
        adapter2.setLabelProvider(proposalLabelProvider);
        adapter2.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);

        // operation combo
        emailOperation2 = new Combo(advancedComposite, SWT.SINGLE | SWT.READ_ONLY | SWT.BORDER);
        emailOperation2.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        emailOperation2.setItems(emailOperationText);
        emailOperation2.setText(emailOperationText[1]);
        emailOperation2.select(1);

        new Label(advancedComposite, SWT.NONE);
        Composite emailComposite2 = new Composite(advancedComposite, SWT.NONE);
        emailComposite2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
        GridLayout emailLayout2 = new GridLayout();
        emailLayout2.marginWidth = 0;
        emailLayout2.marginHeight = 0;
        emailLayout2.horizontalSpacing = 2;
        emailLayout2.numColumns = 5;
        emailComposite2.setLayout(emailLayout2);

        Button e2button0 = new Button(emailComposite2, SWT.CHECK);
        e2button0.setText(Messages.BugzillaSearchPage_owner);

        Button e2button1 = new Button(emailComposite2, SWT.CHECK);
        e2button1.setText(Messages.BugzillaSearchPage_reporter);

        Button e2button2 = new Button(emailComposite2, SWT.CHECK);
        e2button2.setText(Messages.BugzillaSearchPage_cc);

        Button e2button3 = new Button(emailComposite2, SWT.CHECK);
        e2button3.setText(Messages.BugzillaSearchPage_commenter);

        Button e2button4 = new Button(emailComposite2, SWT.CHECK);
        e2button4.setText(Messages.BugzillaSearchPage_qacontact);
        e2button0.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(isPageComplete());
            }
        });
        e2button1.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(isPageComplete());
            }
        });
        e2button2.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(isPageComplete());
            }
        });
        e2button3.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(isPageComplete());
            }
        });
        e2button4.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(isPageComplete());
            }
        });

        emailButtons2 = new Button[] { e2button0, e2button1, e2button2, e2button3, e2button4 };

        new Label(advancedComposite, SWT.NONE);
        Label whiteboardLabel = new Label(advancedComposite, SWT.NONE);
        whiteboardLabel.setText(Messages.BugzillaSearchPage_Whiteboard);

        // whiteboard pattern combo
        whiteboardPattern = new Combo(advancedComposite, SWT.SINGLE | SWT.BORDER);
        whiteboardPattern.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
        whiteboardPattern.addModifyListener(new ModifyListenerImplementation());
        whiteboardPattern.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleWidgetSelected(whiteboardPattern, whiteboardOperation, previousWhiteboardPatterns);
            }
        });

        whiteboardOperation = new Combo(advancedComposite, SWT.READ_ONLY);
        whiteboardOperation.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        whiteboardOperation.setItems(patternOperationText);
        whiteboardOperation.setText(patternOperationText[0]);
        whiteboardOperation.select(0);

        Label keywordsLabel = new Label(advancedComposite, SWT.NONE);
        keywordsLabel.setText(Messages.BugzillaSearchPage_Keywords);

        Composite keywordsComposite = new Composite(advancedComposite, SWT.NONE);
        keywordsComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));
        GridLayout keywordsLayout = new GridLayout();
        keywordsLayout.marginWidth = 0;
        keywordsLayout.marginHeight = 0;
        keywordsLayout.numColumns = 3;
        keywordsComposite.setLayout(keywordsLayout);

        keywordsOperation = new Combo(keywordsComposite, SWT.READ_ONLY);
        keywordsOperation.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
        keywordsOperation.setItems(keywordOperationText);
        keywordsOperation.setText(keywordOperationText[0]);
        keywordsOperation.select(0);

        keywords = new Combo(keywordsComposite, SWT.NONE);
        keywords.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        keywords.addModifyListener(new ModifyListenerImplementation());
        keywords.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleWidgetSelected(keywords, keywordsOperation, previousKeywords);
            }
        });

        final Button keywordsSelectButton = new Button(keywordsComposite, SWT.NONE);
        keywordsSelectButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {

                final java.util.List<String> values = new ArrayList<String>();
                for (String string : keywords.getText().split(",")) { //$NON-NLS-1$
                    values.add(string.trim());
                }

                Map<String, String> validValues = new HashMap<String, String>();
                if (getRepositoryConfiguration() != null) {
                    for (String string : getRepositoryConfiguration().getOptionValues(BugzillaAttribute.KEYWORDS)) {
                        validValues.put(string, string);
                    }
                }
                final InPlaceCheckBoxTreeDialog selectionDialog = new InPlaceCheckBoxTreeDialog(
                        WorkbenchUtil.getShell(), keywordsSelectButton, values, validValues, ""); //$NON-NLS-1$
                selectionDialog.addEventListener(new IInPlaceDialogListener() {

                    public void buttonPressed(InPlaceDialogEvent event) {
                        if (event.getReturnCode() == Window.OK) {
                            Set<String> newValues = selectionDialog.getSelectedValues();
                            if (!new HashSet<String>(values).equals(newValues)) {
                                String erg = ""; //$NON-NLS-1$
                                for (String string : newValues) {
                                    if (erg.equals("")) { //$NON-NLS-1$
                                        erg = string;
                                    } else {
                                        erg += (", " + string); //$NON-NLS-1$
                                    }
                                }
                                keywords.setText(erg);
                            }
                        } else if (event.getReturnCode() == AbstractInPlaceDialog.ID_CLEAR) {
                            keywords.setText(""); //$NON-NLS-1$
                        }
                    }
                });
                selectionDialog.open();

            }
        });
        keywordsSelectButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
        keywordsSelectButton.setText(Messages.BugzillaSearchPage_Select_);

        SashForm bottomForm = new SashForm(advancedComposite, SWT.NONE);
        GridLayout bottomLayout = new GridLayout();
        bottomLayout.numColumns = 6;
        bottomForm.setLayout(bottomLayout);
        GridData bottomLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1);
        bottomLayoutData.heightHint = 80;
        bottomLayoutData.widthHint = 400;
        bottomForm.setLayoutData(bottomLayoutData);

        Composite priorityComposite = new Composite(bottomForm, SWT.NONE);
        GridLayout priorityLayout = new GridLayout();
        priorityLayout.marginWidth = 0;
        priorityLayout.marginHeight = 0;
        priorityLayout.horizontalSpacing = 0;
        priorityComposite.setLayout(priorityLayout);

        Label priorityLabel = new Label(priorityComposite, SWT.LEFT);
        priorityLabel.setText(Messages.BugzillaSearchPage_PROORITY);
        priorityLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        priority = new List(priorityComposite, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
        final GridData gd_priority = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd_priority.heightHint = HEIGHT_ATTRIBUTE_COMBO;
        priority.setLayoutData(gd_priority);
        priority.addSelectionListener(updateActionSelectionAdapter);

        Composite resolutionComposite = new Composite(bottomForm, SWT.NONE);
        GridLayout resolutionLayout = new GridLayout();
        resolutionLayout.marginWidth = 0;
        resolutionLayout.marginHeight = 0;
        resolutionLayout.horizontalSpacing = 0;
        resolutionComposite.setLayout(resolutionLayout);

        Label resolutionLabel = new Label(resolutionComposite, SWT.LEFT);
        resolutionLabel.setText(Messages.BugzillaSearchPage_Resolution);
        resolutionLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        resolution = new List(resolutionComposite, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
        final GridData gd_resolution = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd_resolution.heightHint = HEIGHT_ATTRIBUTE_COMBO;
        resolution.setLayoutData(gd_resolution);
        resolution.addSelectionListener(updateActionSelectionAdapter);

        Composite versionComposite = new Composite(bottomForm, SWT.NONE);
        GridLayout versionLayout = new GridLayout();
        versionLayout.marginWidth = 0;
        versionLayout.marginHeight = 0;
        versionLayout.horizontalSpacing = 0;
        versionComposite.setLayout(versionLayout);

        Label versionLabel = new Label(versionComposite, SWT.LEFT);
        versionLabel.setText(Messages.BugzillaSearchPage_Version);
        versionLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        version = new List(versionComposite, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
        GridData versionLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
        versionLayoutData.heightHint = HEIGHT_ATTRIBUTE_COMBO;
        version.setLayoutData(versionLayoutData);
        version.addSelectionListener(updateActionSelectionAdapter);

        Composite milestoneComposite = new Composite(bottomForm, SWT.NONE);
        GridLayout milestoneLayout = new GridLayout();
        milestoneLayout.marginWidth = 0;
        milestoneLayout.marginHeight = 0;
        milestoneLayout.horizontalSpacing = 0;
        milestoneComposite.setLayout(milestoneLayout);

        Label milestoneLabel = new Label(milestoneComposite, SWT.LEFT);
        milestoneLabel.setText(Messages.BugzillaSearchPage_Milestone);
        milestoneLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        target = new List(milestoneComposite, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
        GridData targetLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
        targetLayoutData.heightHint = HEIGHT_ATTRIBUTE_COMBO;
        target.setLayoutData(targetLayoutData);
        target.addSelectionListener(updateActionSelectionAdapter);

        Composite hardwareComposite = new Composite(bottomForm, SWT.NONE);
        GridLayout hardwareLayout = new GridLayout();
        hardwareLayout.marginWidth = 0;
        hardwareLayout.marginHeight = 0;
        hardwareLayout.horizontalSpacing = 0;
        hardwareComposite.setLayout(hardwareLayout);

        Label hardwareLabel = new Label(hardwareComposite, SWT.LEFT);
        hardwareLabel.setText(Messages.BugzillaSearchPage_Hardware);
        hardwareLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        hardware = new List(hardwareComposite, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
        final GridData gd_hardware = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd_hardware.heightHint = HEIGHT_ATTRIBUTE_COMBO;
        hardware.setLayoutData(gd_hardware);
        hardware.addSelectionListener(updateActionSelectionAdapter);

        Composite osComposite = new Composite(bottomForm, SWT.NONE);
        GridLayout osLayout = new GridLayout();
        osLayout.marginWidth = 0;
        osLayout.marginHeight = 0;
        osLayout.horizontalSpacing = 0;
        osComposite.setLayout(osLayout);

        Label osLabel = new Label(osComposite, SWT.LEFT);
        osLabel.setText(Messages.BugzillaSearchPage_Operating_System);
        osLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        os = new List(osComposite, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
        final GridData gd_os = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd_os.heightHint = HEIGHT_ATTRIBUTE_COMBO;
        os.setLayoutData(gd_os);
        os.addSelectionListener(updateActionSelectionAdapter);
    }

    private void createMoreOptionsChangedInFilter(Composite control) {
        Composite composite = new Composite(control, SWT.NONE);
        GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
        gd.horizontalSpan = 4;
        composite.setLayoutData(gd);
        GridLayout gridLayout = new GridLayout();
        gridLayout.marginTop = 7;
        gridLayout.marginHeight = 0;
        gridLayout.marginWidth = 0;
        gridLayout.numColumns = 3;
        composite.setLayout(gridLayout);

        Label changedInTheLabel = new Label(composite, SWT.LEFT);
        changedInTheLabel.setLayoutData(new GridData());
        changedInTheLabel.setText(Messages.BugzillaSearchPage_Changed_in);

        Composite updateComposite = new Composite(composite, SWT.NONE);
        updateComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        GridLayout updateLayout = new GridLayout(2, false);
        updateLayout.marginWidth = 0;
        updateLayout.horizontalSpacing = 0;
        updateLayout.marginHeight = 0;
        updateComposite.setLayout(updateLayout);

        daysText = new Text(updateComposite, SWT.BORDER);
        daysText.setLayoutData(new GridData(40, SWT.DEFAULT));
        daysText.setTextLimit(5);
        daysText.addListener(SWT.Modify, this);

        Label label = new Label(updateComposite, SWT.LEFT);
        label.setText(Messages.BugzillaSearchPage_days);

    }

    /**
     * Creates the buttons for remembering a query and accessing previously saved queries.
     */
    protected Control createSaveQuery(Composite control) {
        GridLayout layout;
        GridData gd;

        Group group = new Group(control, SWT.NONE);
        layout = new GridLayout(3, false);
        group.setLayout(layout);
        group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        gd = new GridData(GridData.BEGINNING | GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
        gd.horizontalSpan = 2;
        group.setLayoutData(gd);
        return group;
    }

    private void handleWidgetSelected(Combo widget, Combo operation, ArrayList<BugzillaSearchData> history) {
        if (widget.getSelectionIndex() < 0) {
            return;
        }
        int index = history.size() - 1 - widget.getSelectionIndex();
        BugzillaSearchData patternData = history.get(index);
        if (patternData == null || !widget.getText().equals(patternData.pattern)) {
            return;
        }
        widget.setText(patternData.pattern);
        operation.setText(operation.getItem(patternData.operation));
    }

    // TODO: avoid overriding?
    @Override
    public boolean performSearch() {
        if (restoreQueryOptions) {
            saveState();
        }

        getPatternData(summaryPattern, summaryOperation, previousSummaryPatterns);
        getPatternData(commentPattern, commentOperation, previousCommentPatterns);
        getPatternData(emailPattern, emailOperation, previousEmailPatterns);
        getPatternData(emailPattern2, emailOperation2, previousEmailPatterns2);
        getPatternData(keywords, keywordsOperation, previousKeywords);
        getPatternData(whiteboardPattern, whiteboardOperation, previousWhiteboardPatterns);

        String summaryText = summaryPattern.getText();
        BugzillaUiPlugin.getDefault().getPreferenceStore().setValue(IBugzillaConstants.MOST_RECENT_QUERY,
                summaryText);

        return super.performSearch();
    }

    @Override
    public void setVisible(boolean visible) {
        if (visible && summaryPattern != null) {
            if (firstTime) {
                firstTime = false;
                // restore items from history here to prevent page from resizing
                for (String searchPattern : getPreviousPatterns(previousSummaryPatterns)) {
                    summaryPattern.add(searchPattern);
                }
                for (String comment : getPreviousPatterns(previousCommentPatterns)) {
                    commentPattern.add(comment);
                }
                for (String email : getPreviousPatterns(previousEmailPatterns)) {
                    emailPattern.add(email);
                }
                for (String email : getPreviousPatterns(previousEmailPatterns2)) {
                    emailPattern2.add(email);
                }
                for (String keyword : getPreviousPatterns(previousKeywords)) {
                    keywords.add(keyword);
                }

            }
        }
        super.setVisible(visible);
    }

    /**
     * Returns <code>true</code> if at least some parameter is given to query on.
     */
    private boolean canQuery() {
        if (isControlCreated()) {
            return product.getSelectionCount() > 0 || component.getSelectionCount() > 0
                    || version.getSelectionCount() > 0 || target.getSelectionCount() > 0
                    || status.getSelectionCount() > 0 || resolution.getSelectionCount() > 0
                    || severity.getSelectionCount() > 0 || priority.getSelectionCount() > 0
                    || hardware.getSelectionCount() > 0 || os.getSelectionCount() > 0
                    || summaryPattern.getText().length() > 0 || commentPattern.getText().length() > 0
                    || emailPattern.getText().length() > 0 || emailPattern2.getText().length() > 0
                    || keywords.getText().length() > 0;
        } else {
            return false;
        }
    }

    @Override
    public boolean isPageComplete() {
        setMessage(""); //$NON-NLS-1$
        if (errorDecorations.size() > 0) {
            for (ControlDecoration decoration : errorDecorations) {
                decoration.hide();
                decoration.dispose();
            }
            errorDecorations.clear();
        }
        if (daysText != null) {
            String days = daysText.getText();
            if (days.length() > 0) {
                try {
                    if (Integer.parseInt(days) < 0) {
                        throw new NumberFormatException();
                    }
                } catch (NumberFormatException ex) {
                    if (getContainer() != null) {
                        setMessage(NLS.bind(Messages.BugzillaSearchPage_Number_of_days_must_be_a_positive_integer,
                                days), IMessageProvider.ERROR);
                    } else {
                        ErrorDialog.openError(getShell(), Messages.BugzillaSearchPage_ValidationTitle,
                                Messages.BugzillaSearchPage_Number_of_days_is_invalid,
                                new Status(IStatus.ERROR, BugzillaUiPlugin.ID_PLUGIN, NLS.bind(
                                        Messages.BugzillaSearchPage_days_must_be_an_positve_integer_value_but_is,
                                        days)));

                    }
                    return false;
                }
            }
        }
        if (emailPattern != null) {
            String email = emailPattern.getText();
            if (email.length() > 0) {
                boolean selectionMade = false;
                for (Button button : emailButtons) {
                    if (button.getSelection()) {
                        selectionMade = true;
                        break;
                    }
                }
                if (!selectionMade) {
                    FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault();
                    FieldDecoration fieldDecoration = registry
                            .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
                    final ControlDecoration decoration = new ControlDecoration(emailPattern, SWT.LEFT | SWT.DOWN);
                    decoration.setImage(fieldDecoration.getImage());
                    decoration.setDescriptionText(NLS.bind(Messages.BugzillaSearchPage_ValidationMessage,
                            new String[] { Messages.BugzillaSearchPage_Email.replace('&', ' '),
                                    Messages.BugzillaSearchPage_owner, Messages.BugzillaSearchPage_reporter,
                                    Messages.BugzillaSearchPage_cc, Messages.BugzillaSearchPage_commenter,
                                    Messages.BugzillaSearchPage_qacontact }));
                    errorDecorations.add(decoration);
                    if (getContainer() != null) {
                        setMessage(NLS.bind(Messages.BugzillaSearchPage_ValidationMessage,
                                new String[] { Messages.BugzillaSearchPage_Email.replace('&', ' '),
                                        Messages.BugzillaSearchPage_owner, Messages.BugzillaSearchPage_reporter,
                                        Messages.BugzillaSearchPage_cc, Messages.BugzillaSearchPage_commenter,
                                        Messages.BugzillaSearchPage_qacontact }),
                                IMessageProvider.ERROR);
                    }
                    return false;
                }
            }
        }
        if (emailPattern2 != null) {
            String email2 = emailPattern2.getText();
            if (email2.length() > 0) {
                boolean selectionMade = false;
                for (Button button : emailButtons2) {
                    if (button.getSelection()) {
                        selectionMade = true;
                        break;
                    }
                }
                if (!selectionMade) {
                    FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault();
                    FieldDecoration fieldDecoration = registry
                            .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
                    final ControlDecoration decoration = new ControlDecoration(emailPattern, SWT.LEFT | SWT.DOWN);
                    decoration.setImage(fieldDecoration.getImage());
                    decoration.setDescriptionText(NLS.bind(Messages.BugzillaSearchPage_ValidationMessage,
                            new String[] { Messages.BugzillaSearchPage_Email_2.replace('&', ' '),
                                    Messages.BugzillaSearchPage_owner, Messages.BugzillaSearchPage_reporter,
                                    Messages.BugzillaSearchPage_cc, Messages.BugzillaSearchPage_commenter,
                                    Messages.BugzillaSearchPage_qacontact }));
                    errorDecorations.add(decoration);
                    if (getContainer() != null) {
                        setMessage(NLS.bind(Messages.BugzillaSearchPage_ValidationMessage,
                                new String[] { Messages.BugzillaSearchPage_Email_2.replace('&', ' '),
                                        Messages.BugzillaSearchPage_owner, Messages.BugzillaSearchPage_reporter,
                                        Messages.BugzillaSearchPage_cc, Messages.BugzillaSearchPage_commenter,
                                        Messages.BugzillaSearchPage_qacontact }),
                                IMessageProvider.ERROR);
                    }
                    return false;
                }
            }
        }
        if (getWizard() == null) {
            return canQuery();
        } else {
            if (super.isPageComplete()) {
                if (canQuery()) {
                    return true;
                }
            }
            return false;
        }
    }

    /**
     * Return search pattern data and update search history list. An existing entry will be updated or a new one
     * created.
     */
    private BugzillaSearchData getPatternData(Combo widget, Combo operation,
            ArrayList<BugzillaSearchData> previousSearchQueryData) {
        String pattern = widget.getText();
        if (pattern == null || pattern.trim().equals("")) { //$NON-NLS-1$
            return null;
        }
        BugzillaSearchData match = null;
        int i = previousSearchQueryData.size() - 1;
        while (i >= 0) {
            match = previousSearchQueryData.get(i);
            if (pattern.equals(match.pattern)) {
                break;
            }
            i--;
        }
        if (i >= 0 && match != null) {
            match.operation = operation.getSelectionIndex();
            // remove - will be added last (see below)
            previousSearchQueryData.remove(match);
        } else {
            match = new BugzillaSearchData(widget.getText(), operation.getSelectionIndex());
        }
        previousSearchQueryData.add(match);
        return match;
    }

    /**
     * Returns an array of previous summary patterns
     */
    private String[] getPreviousPatterns(ArrayList<BugzillaSearchData> patternHistory) {
        int size = patternHistory.size();
        String[] patterns = new String[size];
        for (int i = 0; i < size; i++) {
            patterns[i] = (patternHistory.get(size - 1 - i)).pattern;
        }
        return patterns;
    }

    public String getSearchURL(TaskRepository repository) {
        return getQueryURL(repository, getQueryParameters());
    }

    protected String getQueryURL(TaskRepository repository, StringBuilder params) {
        StringBuilder url = new StringBuilder(getQueryURLStart(repository).toString());
        url.append(params);

        // HACK make sure that the searches come back sorted by priority. This
        // should be a search option though
        url.append("&order=Importance"); //$NON-NLS-1$
        // url.append(BugzillaRepositoryUtil.contentTypeRDF);
        return url.toString();
    }

    /**
     * Creates the bugzilla query URL start. Example: https://bugs.eclipse.org/bugs/buglist.cgi?
     */
    private StringBuilder getQueryURLStart(TaskRepository repository) {
        StringBuilder sb = new StringBuilder(repository.getRepositoryUrl());

        if (sb.charAt(sb.length() - 1) != '/') {
            sb.append('/');
        }
        sb.append("buglist.cgi?"); //$NON-NLS-1$
        return sb;
    }

    /**
     * Goes through the query form and builds up the query parameters. Example:
     * short_desc_type=substring&amp;short_desc=bla&amp; ... TODO: The encoding here should match
     * TaskRepository.getCharacterEncoding()
     * 
     * @throws UnsupportedEncodingException
     */
    protected StringBuilder getQueryParameters() {
        StringBuilder sb = new StringBuilder();

        sb.append("short_desc_type="); //$NON-NLS-1$
        sb.append(patternOperationValues[summaryOperation.getSelectionIndex()]);
        appendToBuffer(sb, "&short_desc=", summaryPattern.getText()); //$NON-NLS-1$

        int[] selected = product.getSelectionIndices();
        for (int element : selected) {
            appendToBuffer(sb, "&product=", product.getItem(element)); //$NON-NLS-1$
        }

        selected = component.getSelectionIndices();
        for (int element : selected) {
            appendToBuffer(sb, "&component=", component.getItem(element)); //$NON-NLS-1$
        }

        selected = version.getSelectionIndices();
        for (int element : selected) {
            appendToBuffer(sb, "&version=", version.getItem(element)); //$NON-NLS-1$
        }

        selected = target.getSelectionIndices();
        for (int element : selected) {
            appendToBuffer(sb, "&target_milestone=", target.getItem(element)); //$NON-NLS-1$
        }

        sb.append("&long_desc_type="); //$NON-NLS-1$
        sb.append(patternOperationValues[commentOperation.getSelectionIndex()]);
        appendToBuffer(sb, "&long_desc=", commentPattern.getText()); //$NON-NLS-1$

        selected = status.getSelectionIndices();
        for (int element : selected) {
            appendToBuffer(sb, "&bug_status=", status.getItem(element)); //$NON-NLS-1$
        }

        selected = resolution.getSelectionIndices();
        for (int element : selected) {
            appendToBuffer(sb, "&resolution=", resolution.getItem(element)); //$NON-NLS-1$
        }

        selected = severity.getSelectionIndices();
        for (int element : selected) {
            appendToBuffer(sb, "&bug_severity=", severity.getItem(element)); //$NON-NLS-1$
        }

        selected = priority.getSelectionIndices();
        for (int element : selected) {
            appendToBuffer(sb, "&priority=", priority.getItem(element)); //$NON-NLS-1$
        }

        selected = hardware.getSelectionIndices();
        for (int element : selected) {
            appendToBuffer(sb, "&rep_platform=", hardware.getItem(element)); //$NON-NLS-1$
        }

        selected = os.getSelectionIndices();
        for (int element : selected) {
            appendToBuffer(sb, "&op_sys=", os.getItem(element)); //$NON-NLS-1$
        }

        if (emailPattern.getText() != null && !emailPattern.getText().trim().equals("")) { //$NON-NLS-1$
            boolean selectionMade = false;
            for (Button button : emailButtons) {
                if (button.getSelection()) {
                    selectionMade = true;
                    break;
                }
            }
            if (selectionMade) {
                for (int i = 0; i < emailButtons.length; i++) {
                    if (emailButtons[i].getSelection()) {
                        sb.append("&"); //$NON-NLS-1$
                        sb.append(emailRoleValues[i]);
                        sb.append("=1"); //$NON-NLS-1$
                    }
                }
                sb.append("&emailtype1="); //$NON-NLS-1$
                sb.append(emailOperationValues[emailOperation.getSelectionIndex()]);
                appendToBuffer(sb, "&email1=", emailPattern.getText()); //$NON-NLS-1$
            }
        }

        if (emailPattern2.getText() != null && !emailPattern2.getText().trim().equals("")) { //$NON-NLS-1$
            boolean selectionMade = false;
            for (Button button : emailButtons2) {
                if (button.getSelection()) {
                    selectionMade = true;
                    break;
                }
            }
            if (selectionMade) {
                for (int i = 0; i < emailButtons2.length; i++) {
                    if (emailButtons2[i].getSelection()) {
                        sb.append("&"); //$NON-NLS-1$
                        sb.append(emailRoleValues2[i]);
                        sb.append("=1"); //$NON-NLS-1$
                    }
                }
                sb.append("&emailtype2="); //$NON-NLS-1$
                sb.append(emailOperationValues[emailOperation2.getSelectionIndex()]);
                appendToBuffer(sb, "&email2=", emailPattern2.getText()); //$NON-NLS-1$
            }
        }

        if (daysText.getText() != null && !daysText.getText().equals("")) { //$NON-NLS-1$
            try {
                Integer.parseInt(daysText.getText());
                appendToBuffer(sb, "&changedin=", daysText.getText()); //$NON-NLS-1$
            } catch (NumberFormatException ignored) {
                // this means that the days is not a number, so don't worry
            }
        }

        if (keywords.getText() != null && !keywords.getText().trim().equals("")) { //$NON-NLS-1$
            sb.append("&keywords_type="); //$NON-NLS-1$
            sb.append(keywordOperationValues[keywordsOperation.getSelectionIndex()]);
            appendToBuffer(sb, "&keywords=", keywords.getText().replace(',', ' ')); //$NON-NLS-1$
        }
        sb.append("&status_whiteboard_type="); //$NON-NLS-1$
        sb.append(patternOperationValues[whiteboardOperation.getSelectionIndex()]);
        appendToBuffer(sb, "&status_whiteboard=", whiteboardPattern.getText()); //$NON-NLS-1$
        int indexMax = charts.size();
        for (int index = 0; index < indexMax; index++) {
            Chart chart = charts.get(index);
            if (chart.isNegate()) {
                sb.append("&negate" + index + "=1"); //$NON-NLS-1$ //$NON-NLS-2$
            }
            int rowMax = chart.getRowSize();
            for (int row = 0; row < rowMax; row++) {
                int columnMax = chart.getColumnSize(row);
                for (int column = 0; column < columnMax; column++) {
                    ChartExpression chartExpression = chart.getChartExpression(row, column);
                    if (chartExpression.getFieldName() == 0) {
                        continue;
                    }
                    sb.append("&field" + index + "-" + row + "-" + column + "=" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
                            + chartFieldValues[chartExpression.getFieldName()]);
                    sb.append("&type" + index + "-" + row + "-" + column + "=" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
                            + chartOperationValues[chartExpression.getOperation()]);
                    sb.append("&value" + index + "-" + row + "-" + column + "=" + chartExpression.getValue()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
                }
            }
        }
        return sb;
    }

    private void appendToBuffer(StringBuilder sb, String key, String value) {
        sb.append(key);
        try {
            sb.append(URLEncoder.encode(value, getTaskRepository().getCharacterEncoding()));
        } catch (UnsupportedEncodingException e) {
            sb.append(value);
        }
    }

    @Override
    public IDialogSettings getDialogSettings() {
        IDialogSettings settings = BugzillaUiPlugin.getDefault().getDialogSettings();
        fDialogSettings = settings.getSection(PAGE_NAME);
        if (fDialogSettings == null) {
            fDialogSettings = settings.addNewSection(PAGE_NAME);
        }
        return fDialogSettings;
    }

    @SuppressWarnings("unchecked")
    private void updateAttributesFromConfiguration(String[] selectedProducts) {
        RepositoryConfiguration repositoryConfiguration = getRepositoryConfiguration();
        if (repositoryConfiguration != null) {
            String[] saved_status = status.getSelection();
            String[] saved_resolution = resolution.getSelection();
            String[] saved_severity = severity.getSelection();
            String[] saved_priority = priority.getSelection();
            String[] saved_hardware = hardware.getSelection();
            String[] saved_os = os.getSelection();

            java.util.List<String> products = repositoryConfiguration.getOptionValues(BugzillaAttribute.PRODUCT);
            String[] productsList = products.toArray(new String[products.size()]);
            Arrays.sort(productsList, String.CASE_INSENSITIVE_ORDER);
            product.setItems(productsList);

            updateAttributesBasedOnProductSelection(selectedProducts, repositoryConfiguration);

            status.setItems(convertStringListToArray(
                    repositoryConfiguration.getOptionValues(BugzillaAttribute.BUG_STATUS)));
            resolution.setItems(convertStringListToArray(
                    repositoryConfiguration.getOptionValues(BugzillaAttribute.RESOLUTION)));
            severity.setItems(convertStringListToArray(
                    repositoryConfiguration.getOptionValues(BugzillaAttribute.BUG_SEVERITY)));
            priority.setItems(
                    convertStringListToArray(repositoryConfiguration.getOptionValues(BugzillaAttribute.PRIORITY)));
            hardware.setItems(convertStringListToArray(
                    repositoryConfiguration.getOptionValues(BugzillaAttribute.REP_PLATFORM)));
            os.setItems(
                    convertStringListToArray(repositoryConfiguration.getOptionValues(BugzillaAttribute.OP_SYS)));

            setSelection(product, selectedProducts);
            setSelection(status, saved_status);
            setSelection(resolution, saved_resolution);
            setSelection(severity, saved_severity);
            setSelection(priority, saved_priority);
            setSelection(hardware, saved_hardware);
            setSelection(os, saved_os);

            ArrayList<String> fieldText = (ArrayList<String>) chartFieldTextDefault.clone();
            ArrayList<String> fieldValue = (ArrayList<String>) chartFieldValuesDefault.clone();

            for (BugzillaCustomField bugzillaCustomField : repositoryConfiguration.getCustomFields()) {
                fieldValue.add(bugzillaCustomField.getName());
                fieldText.add(bugzillaCustomField.getDescription());
            }
            chartFieldText = fieldText.toArray(new String[fieldText.size()]);
            chartFieldValues = fieldValue.toArray(new String[fieldValue.size()]);
            recreateChartControls();
        }
    }

    private void updateAttributesBasedOnProductSelection(String[] selectedProducts,
            RepositoryConfiguration repositoryConfiguration) {
        if (repositoryConfiguration == null) {
            return;
        }

        // show everything if no product is selected
        if (selectedProducts != null && selectedProducts.length == 0) {
            selectedProducts = null;
        }

        String[] saved_component = component.getSelection();
        String[] saved_version = version.getSelection();
        String[] saved_target = target.getSelection();

        String[] componentsList = BugzillaUiPlugin.getQueryOptions(IBugzillaConstants.VALUES_COMPONENT,
                selectedProducts, repositoryConfiguration);
        Arrays.sort(componentsList, String.CASE_INSENSITIVE_ORDER);
        component.setItems(componentsList);
        version.setItems(BugzillaUiPlugin.getQueryOptions(IBugzillaConstants.VALUES_VERSION, selectedProducts,
                repositoryConfiguration));
        target.setItems(BugzillaUiPlugin.getQueryOptions(IBugzillaConstants.VALUES_TARGET, selectedProducts,
                repositoryConfiguration));

        setSelection(component, saved_component);
        setSelection(version, saved_version);
        setSelection(target, saved_target);
    }

    @Override
    public boolean canFlipToNextPage() {
        return false;
    }

    public void handleEvent(Event event) {
        if (getWizard() != null) {
            getWizard().getContainer().updateButtons();
        } else {
            isPageComplete();
        }
    }

    public void restoreStateFromUrl(String queryUrl) throws UnsupportedEncodingException {
        BugzillaSearch search = new BugzillaSearch(getTaskRepository(), queryUrl);

        // set product first to initialize dependent fields
        for (Entry entry : search.getParameters("product")) { //$NON-NLS-1$
            String value = entry.value;
            String[] sel = product.getSelection();
            java.util.List<String> selList = Arrays.asList(sel);
            selList = new ArrayList<String>(selList);
            selList.add(value);
            sel = new String[selList.size()];
            product.setSelection(selList.toArray(sel));
        }

        updateAttributesBasedOnProductSelection(product.getSelection(), getRepositoryConfiguration());

        boolean adjustChart = false;
        for (Entry entry : search.getParameters()) {
            String key = entry.key;
            String value = entry.value;

            if (key.equals("short_desc")) { //$NON-NLS-1$
                summaryPattern.setText(value);
            } else if (key.equals("short_desc_type")) { //$NON-NLS-1$
                int index = 0;
                for (String item : patternOperationValues) {
                    if (item.compareTo(value) == 0) {
                        break;
                    }
                    index++;
                }
                if (index < summaryOperation.getItemCount()) {
                    summaryOperation.select(index);
                }
            } else if (key.equals("product")) { //$NON-NLS-1$
                // ignore, see above
            } else if (key.equals("component")) { //$NON-NLS-1$
                String[] sel = component.getSelection();
                java.util.List<String> selList = Arrays.asList(sel);
                selList = new ArrayList<String>(selList);
                selList.add(value);
                sel = new String[selList.size()];
                component.setSelection(selList.toArray(sel));
            } else if (key.equals("version")) { //$NON-NLS-1$
                String[] sel = version.getSelection();
                java.util.List<String> selList = Arrays.asList(sel);
                selList = new ArrayList<String>(selList);
                selList.add(value);
                sel = new String[selList.size()];
                version.setSelection(selList.toArray(sel));
            } else if (key.equals("target_milestone")) { // XXX //$NON-NLS-1$
                String[] sel = target.getSelection();
                java.util.List<String> selList = Arrays.asList(sel);
                selList = new ArrayList<String>(selList);
                selList.add(value);
                sel = new String[selList.size()];
                target.setSelection(selList.toArray(sel));
            } else if (key.equals("version")) { //$NON-NLS-1$
                String[] sel = version.getSelection();
                java.util.List<String> selList = Arrays.asList(sel);
                selList = new ArrayList<String>(selList);
                selList.add(value);
                sel = new String[selList.size()];
                version.setSelection(selList.toArray(sel));
            } else if (key.equals("long_desc_type")) { //$NON-NLS-1$
                int index = 0;
                for (String item : patternOperationValues) {
                    if (item.compareTo(value) == 0) {
                        break;
                    }
                    index++;
                }
                if (index < commentOperation.getItemCount()) {
                    commentOperation.select(index);
                }
            } else if (key.equals("long_desc")) { //$NON-NLS-1$
                commentPattern.setText(value);
            } else if (key.equals("bug_status")) { //$NON-NLS-1$
                String[] sel = status.getSelection();
                java.util.List<String> selList = Arrays.asList(sel);
                selList = new ArrayList<String>(selList);
                selList.add(value);
                sel = new String[selList.size()];
                status.setSelection(selList.toArray(sel));
            } else if (key.equals("resolution")) { //$NON-NLS-1$
                String[] sel = resolution.getSelection();
                java.util.List<String> selList = Arrays.asList(sel);
                selList = new ArrayList<String>(selList);
                selList.add(value);
                sel = new String[selList.size()];
                resolution.setSelection(selList.toArray(sel));
            } else if (key.equals("bug_severity")) { //$NON-NLS-1$
                String[] sel = severity.getSelection();
                java.util.List<String> selList = Arrays.asList(sel);
                selList = new ArrayList<String>(selList);
                selList.add(value);
                sel = new String[selList.size()];
                severity.setSelection(selList.toArray(sel));
            } else if (key.equals("priority")) { //$NON-NLS-1$
                String[] sel = priority.getSelection();
                java.util.List<String> selList = Arrays.asList(sel);
                selList = new ArrayList<String>(selList);
                selList.add(value);
                sel = new String[selList.size()];
                priority.setSelection(selList.toArray(sel));
            } else if (key.equals("rep_platform")) { //$NON-NLS-1$
                String[] sel = hardware.getSelection();
                java.util.List<String> selList = Arrays.asList(sel);
                selList = new ArrayList<String>(selList);
                selList.add(value);
                sel = new String[selList.size()];
                hardware.setSelection(selList.toArray(sel));
            } else if (key.equals("op_sys")) { //$NON-NLS-1$
                String[] sel = os.getSelection();
                java.util.List<String> selList = Arrays.asList(sel);
                selList = new ArrayList<String>(selList);
                selList.add(value);
                sel = new String[selList.size()];
                os.setSelection(selList.toArray(sel));
            } else if (key.equals("emailassigned_to1")) { // HACK: email //$NON-NLS-1$
                // buttons
                // assumed to be
                // in same
                // position
                if (value.equals("1")) { //$NON-NLS-1$
                    emailButtons[0].setSelection(true);
                } else {
                    emailButtons[0].setSelection(false);
                }
            } else if (key.equals("emailreporter1")) { // HACK: email //$NON-NLS-1$
                // buttons assumed
                // to be in same
                // position
                if (value.equals("1")) { //$NON-NLS-1$
                    emailButtons[1].setSelection(true);
                } else {
                    emailButtons[1].setSelection(false);
                }
            } else if (key.equals("emailcc1")) { // HACK: email buttons //$NON-NLS-1$
                // assumed to be in same
                // position
                if (value.equals("1")) { //$NON-NLS-1$
                    emailButtons[2].setSelection(true);
                } else {
                    emailButtons[2].setSelection(false);
                }
            } else if (key.equals("emaillongdesc1")) { // HACK: email //$NON-NLS-1$
                // buttons assumed
                // to be in same
                // position
                if (value.equals("1")) { //$NON-NLS-1$
                    emailButtons[3].setSelection(true);
                } else {
                    emailButtons[3].setSelection(false);
                }
            } else if (key.equals("emailqa_contact1")) { // HACK: email //$NON-NLS-1$
                // buttons assumed
                // to be in same
                // position
                if (value.equals("1")) { //$NON-NLS-1$
                    emailButtons[4].setSelection(true);
                } else {
                    emailButtons[4].setSelection(false);
                }
            } else if (key.equals("emailtype1")) { //$NON-NLS-1$
                int index = 0;
                for (; index < emailOperationValues.length; index++) {
                    String item = emailOperationValues[index];
                    if (item.compareTo(value) == 0) {
                        break;
                    }
                }
                if (index < emailOperation.getItemCount()) {
                    emailOperation.select(index);
                }
            } else if (key.equals("email1")) { //$NON-NLS-1$
                emailPattern.setText(value);
            } else if (key.equals("emailassigned_to2")) { // HACK: email //$NON-NLS-1$
                // buttons
                // assumed to be
                // in same
                // position
                if (value.equals("1")) { //$NON-NLS-1$
                    emailButtons2[0].setSelection(true);
                } else {
                    emailButtons2[0].setSelection(false);
                }
            } else if (key.equals("emailreporter2")) { // HACK: email //$NON-NLS-1$
                // buttons assumed
                // to be in same
                // position
                if (value.equals("1")) { //$NON-NLS-1$
                    emailButtons2[1].setSelection(true);
                } else {
                    emailButtons2[1].setSelection(false);
                }
            } else if (key.equals("emailcc2")) { // HACK: email buttons //$NON-NLS-1$
                // assumed to be in same
                // position
                if (value.equals("1")) { //$NON-NLS-1$
                    emailButtons2[2].setSelection(true);
                } else {
                    emailButtons2[2].setSelection(false);
                }
            } else if (key.equals("emaillongdesc2")) { // HACK: email //$NON-NLS-1$
                // buttons assumed
                // to be in same
                // position
                if (value.equals("1")) { //$NON-NLS-1$
                    emailButtons2[3].setSelection(true);
                } else {
                    emailButtons2[3].setSelection(false);
                }
            } else if (key.equals("emailqa_contact2")) { // HACK: email //$NON-NLS-1$
                // buttons assumed
                // to be in same
                // position
                if (value.equals("1")) { //$NON-NLS-1$
                    emailButtons2[4].setSelection(true);
                } else {
                    emailButtons2[4].setSelection(false);
                }
            } else if (key.equals("emailtype2")) { //$NON-NLS-1$
                int index = 0;
                for (; index < emailOperationValues.length; index++) {
                    String item = emailOperationValues[index];
                    if (item.compareTo(value) == 0) {
                        break;
                    }
                }
                if (index < emailOperation2.getItemCount()) {
                    emailOperation2.select(index);
                }
            } else if (key.equals("email2")) { //$NON-NLS-1$
                emailPattern2.setText(value);
            } else if (key.equals("changedin")) { //$NON-NLS-1$
                daysText.setText(value);
            } else if (key.equals("keywords")) { //$NON-NLS-1$
                keywords.setText(value.replace(' ', ','));
            } else if (key.equals("keywords_type")) { //$NON-NLS-1$
                int index = 0;
                for (String item : keywordOperationValues) {
                    if (item.equals(value)) {
                        keywordsOperation.select(index);
                        break;
                    }
                    index++;
                }
            } else if (key.equals("status_whiteboard_type")) { //$NON-NLS-1$
                int index = 0;
                for (String item : patternOperationValues) {
                    if (item.compareTo(value) == 0) {
                        break;
                    }
                    index++;
                }
                if (index < whiteboardOperation.getItemCount()) {
                    whiteboardOperation.select(index);
                }
            } else if (key.equals("status_whiteboard")) { //$NON-NLS-1$
                whiteboardPattern.setText(value);
            } else if (key.matches(REGEXP_CHART_EXPR)) {
                Matcher mb = PATTERN_CHART_EXPR.matcher(key);
                if (mb.find()) {
                    String g1 = mb.group(1);
                    String g2 = mb.group(2);
                    String g3 = mb.group(3);
                    String g4 = mb.group(4);
                    int chartNumber, row, column;
                    try {
                        chartNumber = Integer.parseInt(g2);
                        row = Integer.parseInt(g3);
                        column = Integer.parseInt(g4);
                    } catch (Exception E) {
                        chartNumber = -1;
                        row = -1;
                        column = -1;
                    }
                    for (int i = charts.size(); i <= chartNumber; i++) {
                        charts.add(new Chart());
                        adjustChart = true;
                    }
                    for (int i = charts.get(chartNumber).getRowSize(); i <= row; i++) {
                        charts.get(chartNumber).addExpression(i, 0);
                        adjustChart = true;
                    }
                    for (int i = charts.get(chartNumber).getColumnSize(row); i <= column; i++) {
                        charts.get(chartNumber).addExpression(row, i);
                        adjustChart = true;
                    }
                    ChartExpression ex = charts.get(chartNumber).getChartExpression(row, column);
                    if ("field".equals(g1)) { //$NON-NLS-1$
                        int index1 = 0;
                        for (String item : chartFieldValues) {
                            if (item.compareTo(value) == 0) {
                                break;
                            }
                            index1++;
                        }
                        if (index1 < chartFieldValues.length) {
                            ex.setFieldName(index1);
                        }
                    } else if ("type".equals(g1)) { //$NON-NLS-1$
                        int index1 = 0;
                        for (String item : chartOperationValues) {
                            if (item.compareTo(value) == 0) {
                                break;
                            }
                            index1++;
                        }
                        if (index1 < chartOperationValues.length) {
                            ex.setOperation(index1);
                        }
                    } else if ("value".equals(g1)) { //$NON-NLS-1$
                        ex.setValue(value);
                    }

                }
            } else if (key.matches(REGEXP_CHART_NEGATE)) {
                Matcher mb = PATTERN_CHART_NEGATE.matcher(key);
                if (mb.find()) {
                    String g2 = mb.group(2);
                    int index;
                    try {
                        index = Integer.parseInt(g2);
                    } catch (Exception E) {
                        index = -1;
                    }
                    Chart ch = charts.get(index);
                    ch.setNegate("1".equals(value)); //$NON-NLS-1$
                }
            }
        }
        if (adjustChart) {
            recreateChartControls();
        }
    }

    /* Testing hook to see if any products are present */
    public int getProductCount() throws Exception {
        return product.getItemCount();
    }

    public boolean isRestoreQueryOptions() {
        return restoreQueryOptions;
    }

    public void setRestoreQueryOptions(boolean restoreQueryOptions) {
        this.restoreQueryOptions = restoreQueryOptions;
    }

    private String[] convertStringListToArray(java.util.List<String> stringList) {
        return stringList.toArray(new String[stringList.size()]);
    }

    private void setSelection(List listControl, String[] selection) {
        listControl.setSelection(selection);
    }

    @Override
    public void dispose() {
        if (toolkit != null) {
            if (toolkit.getColors() != null) {
                toolkit.dispose();
            }
        }
        super.dispose();
    }

    private void refreshChartControls() {
        int chartNumMax = chartControls.size();
        for (int chartNum = 0; chartNum < chartNumMax; chartNum++) {
            int chartRowMax = chartControls.get(chartNum).size();
            for (int chartRow = 0; chartRow < chartRowMax; chartRow++) {
                int chartColumnMax = chartControls.get(chartNum).get(chartRow).size();
                for (int chartColumn = 0; chartColumn < chartColumnMax; chartColumn++) {
                    ChartExpression expression = charts.get(chartNum).getChartExpression(chartRow, chartColumn);
                    ChartControls controls = chartControls.get(chartNum).get(chartRow).get(chartColumn);
                    controls.getField().setText(chartFieldText[expression.getFieldName()]);
                    controls.getOperation().setText(chartOperationText[expression.getOperation()]);
                    controls.getValue().setText(expression.getValue());
                }
            }
        }
        int negButtonMax = negateButtons.size();
        for (int chartNum = 0; chartNum < negButtonMax; chartNum++) {
            Button b = negateButtons.get(chartNum);
            Chart c = charts.get(chartNum);
            b.setSelection(c.isNegate());
        }
        scrolledComposite.reflow(true);
    }

    private void recreateChartControls() {
        GridLayout layout;
        GridData gd;

        if (chartSection.getClient() != null) {
            chartSection.getClient().dispose();
        }

        chartControls.clear();
        negateButtons.clear();

        Composite chartGroup = new Composite(chartSection, SWT.NONE);
        layout = new GridLayout(1, false);
        layout.verticalSpacing = 0;
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        chartGroup.setLayout(layout);
        chartSection.setClient(chartGroup);

        int chartNumMax = charts.size();
        for (int chartNumber = 0; chartNumber < chartNumMax; chartNumber++) {
            final int chartNum = chartNumber;
            final Composite chartGroup0 = new Composite(chartGroup, SWT.NONE);
            if (chartNum > 0) {
                // separator
                Label sep = new Label(chartGroup0, SWT.NONE);
                sep.setText(" "); //$NON-NLS-1$
                gd = new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1);
                sep.setLayoutData(gd);
            }
            layout = new GridLayout(3, false);
            layout.marginHeight = 0;
            layout.marginWidth = 0;
            chartGroup0.setLayout(layout);
            gd = new GridData(GridData.FILL, GridData.FILL, true, true, 3, 1);
            chartGroup0.setLayoutData(gd);
            final int chartRowMax = charts.get(chartNum).getRowSize();
            for (int chartRowNumber = 0; chartRowNumber < chartRowMax; chartRowNumber++) {
                final int chartRow = chartRowNumber;
                int chartColumnMax = charts.get(chartNum).getColumnSize(chartRow);
                final Group chartGroup1 = new Group(chartGroup0, SWT.NONE);
                layout = new GridLayout(4, false);
                chartGroup1.setLayout(layout);
                gd = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1);
                chartGroup1.setLayoutData(gd);
                for (int chartColumnNumber = 0; chartColumnNumber < chartColumnMax; chartColumnNumber++) {
                    final int chartColumn = chartColumnNumber;
                    final Combo comboField = new Combo(chartGroup1, SWT.SINGLE | SWT.BORDER);
                    comboField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
                    comboField.addModifyListener(new ModifyListenerImplementation());
                    comboField.setItems(chartFieldText);
                    comboField.setText(chartFieldText[0]);
                    comboField.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            ChartExpression chartExpression = charts.get(chartNum).getChartExpression(chartRow,
                                    chartColumn);
                            chartExpression.setFieldName(comboField.getSelectionIndex());
                            comboField.getShell().layout(true);
                            comboField.getShell().redraw();
                        }
                    });
                    comboField.setToolTipText(Messages.BugzillaSearchPage_Tooltip_Custom_fields_at_end);

                    final Combo comboOperation = new Combo(chartGroup1, SWT.SINGLE | SWT.READ_ONLY | SWT.BORDER);
                    comboOperation.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
                    comboOperation.setItems(chartOperationText);
                    comboOperation.setText(chartOperationText[0]);
                    comboOperation.select(0);
                    comboOperation.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            ChartExpression chartExpression = charts.get(chartNum).getChartExpression(chartRow,
                                    chartColumn);
                            chartExpression.setOperation(comboOperation.getSelectionIndex());
                        }
                    });
                    final Combo comboValue = new Combo(chartGroup1, SWT.SINGLE | SWT.BORDER);
                    gd = new GridData(GridData.FILL, GridData.CENTER, true, false);
                    gd.widthHint = 150;
                    comboValue.setLayoutData(gd);
                    comboValue.addModifyListener(new ModifyListener() {

                        public void modifyText(ModifyEvent e) {
                            ChartExpression chartExpression = charts.get(chartNum).getChartExpression(chartRow,
                                    chartColumn);
                            chartExpression.setValue(comboValue.getText());
                            if (isControlCreated()) {
                                setPageComplete(isPageComplete());
                            }
                        }
                    });
                    Button orButton = new Button(chartGroup1, SWT.PUSH);
                    orButton.setText(Messages.BugzillaSearchPage_OR_Button);
                    gd = new GridData(SWT.LEFT, SWT.CENTER, false, false);
                    orButton.setLayoutData(gd);
                    orButton.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            if (e.stateMask == SWT.SHIFT) {
                                if (charts.size() == 1 && charts.get(0).getRowSize() == 1
                                        && charts.get(0).getColumnSize(0) == 1) {
                                    return;
                                }
                                charts.get(chartNum).removeColumn(chartRow, chartColumn);
                                if (charts.get(chartNum).getRowSize() == 0) {
                                    if (chartNum != 0) {
                                        charts.remove(chartNum);
                                    }
                                }
                            } else {
                                charts.get(chartNum).addExpression(chartRow, chartColumn + 1);
                            }
                            recreateChartControls();
                        }
                    });
                    orButton.setToolTipText(Messages.BugzillaSearchPage_Tooltip_remove_row);
                    ChartControls chartControl = new ChartControls(comboField, comboOperation, comboValue);
                    int chart1 = chartControls.size();
                    if (chart1 < chartNum + 1) {
                        chartControls.add(new ArrayList<ArrayList<ChartControls>>());
                    }
                    int chart2 = chartControls.get(chartNum).size();
                    if (chart2 < chartRow + 1) {
                        chartControls.get(chartNum).add(new ArrayList<BugzillaSearchPage.ChartControls>());
                    }
                    chartControls.get(chartNum).get(chartRow).add(chartControl);
                }
                if (chartRowNumber < chartRowMax - 1) {
                    Label lable = new Label(chartGroup0, SWT.NONE);
                    lable.setText(Messages.BugzillaSearchPage_AND_Button);
                    GridData g = new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1);
                    lable.setLayoutData(g);
                } else {
                    final Button andButton = new Button(chartGroup0, SWT.PUSH);
                    andButton.setText(Messages.BugzillaSearchPage_AND_Button);
                    gd = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
                    andButton.setLayoutData(gd);
                    final Button newButton = new Button(chartGroup0, SWT.PUSH);
                    newButton.setText(Messages.BugzillaSearchPage_Add_Chart_Button);
                    gd = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
                    newButton.setLayoutData(gd);
                    final Button negateButton = new Button(chartGroup0, SWT.CHECK);
                    negateButton.setText(Messages.BugzillaSearchPage_Negate_Button);
                    negateButtons.add(negateButton);
                    gd = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
                    negateButton.setLayoutData(gd);
                    negateButton.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            Chart chart = charts.get(chartNum);
                            chart.setNegate(negateButton.getSelection());
                        }
                    });
                    newButton.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            newButton.setVisible(false);
                            newButton.dispose();
                            charts.add(chartNum + 1, new Chart());
                            recreateChartControls();
                        }
                    });
                    andButton.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            charts.get(chartNum).addExpression(chartRow + 1, 0);
                            recreateChartControls();

                        }
                    });
                }
            }

        }
        chartSection.layout(true);
        scrolledComposite.reflow(true);
        refreshChartControls();
        Dialog.applyDialogFont(chartSection);
    }

    public BugzillaSearchPage(TaskRepository repository) {
        this(repository, null);
    }

    public BugzillaSearchPage(TaskRepository repository, IRepositoryQuery origQuery) {
        super(Messages.BugzillaSearchPage_Bugzilla_Query, repository, origQuery);
        this.originalQuery = origQuery;

        setNeedsClear(true);
        setDescription(Messages.BugzillaSearchPage_Select_the_Bugzilla_query_parameters);
        setMessage(Messages.BugzillaSearchPage_Enter_search_option);

        toolkit = new FormToolkit(Display.getCurrent());
    }

    @Override
    protected boolean hasRepositoryConfiguration() {
        return getRepositoryConfiguration() != null;
    }

    public RepositoryConfiguration getRepositoryConfiguration() {
        return ((BugzillaRepositoryConnector) getConnector())
                .getRepositoryConfiguration(getTaskRepository().getUrl());
    }

    @Override
    protected void doRefreshControls() {
        updateAttributesFromConfiguration(product.getSelection());
    }

    @Override
    protected boolean restoreState(IRepositoryQuery query) {
        if (query != null) {
            try {
                restoreStateFromUrl(query.getUrl());
            } catch (UnsupportedEncodingException e) {
                // ignore
            }
        }

        boolean reflow = false;
        if (commentPattern.getText().length() > 0 || emailPattern2.getText().length() > 0
                || keywords.getText().length() > 0 || whiteboardPattern.getText().length() > 0
                || priority.getSelection().length > 0 || resolution.getSelection().length > 0
                || version.getSelection().length > 0 || target.getSelection().length > 0
                || hardware.getSelection().length > 0 || os.getSelection().length > 0) {
            moreOptionsSection.setExpanded(true);
            reflow = true;
        }

        if (charts.size() > 0 && charts.get(0).getChartExpression(0, 0).getFieldName() > 0) {
            chartSection.setExpanded(true);
            reflow = true;
        }

        if (reflow) {
            scrolledComposite.reflow(true);
        }
        refreshChartControls();

        setPageComplete(isPageComplete());

        return true;
    }

    @Override
    public void applyTo(IRepositoryQuery query) {
        query.setUrl(getQueryURL(getTaskRepository(), getQueryParameters()));
        query.setSummary(getQueryTitle());
    }

}