1/*******************************************************************************
2 * Copyright (c) 2000, 2009 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *     IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.test.internal.performance.results.ui;
12
13import java.io.File;
14import java.util.Arrays;
15import java.util.Iterator;
16
17import org.osgi.service.prefs.BackingStoreException;
18
19import org.eclipse.test.internal.performance.PerformanceTestPlugin;
20import org.eclipse.test.internal.performance.results.db.DB_Results;
21import org.eclipse.test.internal.performance.results.utils.IPerformancesConstants;
22import org.eclipse.test.internal.performance.results.utils.Util;
23import org.eclipse.test.performance.ui.UiPlugin;
24
25import org.eclipse.swt.SWT;
26import org.eclipse.swt.custom.CCombo;
27import org.eclipse.swt.events.ModifyEvent;
28import org.eclipse.swt.events.ModifyListener;
29import org.eclipse.swt.events.SelectionEvent;
30import org.eclipse.swt.events.SelectionListener;
31import org.eclipse.swt.layout.GridData;
32import org.eclipse.swt.layout.GridLayout;
33import org.eclipse.swt.widgets.Button;
34import org.eclipse.swt.widgets.Composite;
35import org.eclipse.swt.widgets.Control;
36import org.eclipse.swt.widgets.DirectoryDialog;
37import org.eclipse.swt.widgets.Display;
38import org.eclipse.swt.widgets.Group;
39import org.eclipse.swt.widgets.Label;
40import org.eclipse.swt.widgets.List;
41import org.eclipse.swt.widgets.Text;
42
43import org.eclipse.core.runtime.preferences.IEclipsePreferences;
44import org.eclipse.core.runtime.preferences.InstanceScope;
45
46import org.eclipse.jface.dialogs.MessageDialog;
47import org.eclipse.jface.preference.IPreferenceStore;
48import org.eclipse.jface.preference.PreferencePage;
49
50import org.eclipse.ui.IWorkbench;
51import org.eclipse.ui.IWorkbenchPreferencePage;
52
53/**
54 * Defines the 'Performances' preferences page.
55 */
56public class PerformanceResultsPreferencePage extends PreferencePage
57	implements IWorkbenchPreferencePage, SelectionListener, ModifyListener, IPerformancesConstants {
58
59	private Button mVersionRadioButton;
60	private Button dVersionRadionButton;
61	private CCombo databaseLocationCombo;
62	private Button dbConnectionCheckBox;
63	private Button dbLocalBrowseButton;
64	private Button dbRelengRadioButton;
65	private Button dbLocalRadioButton;
66	private CCombo defaultDimensionCombo;
67	private CCombo lastBuildCombo;
68	private List resultsDimensionsList;
69	private CCombo milestonesCombo;
70	private Label dbLocationLabel;
71
72	// Status SWT objects
73	private Button statusValuesCheckBox;
74	private Button statusErrorNoneRadioButton;
75	private Button statusErrorNoticeableRadioButton;
76	private Button statusErrorSuspiciousRadioButton;
77	private Button statusErrorWeirdRadioButton;
78	private Button statusErrorInvalidRadioButton;
79	private Button statusSmallBuildValueCheckBox;
80	private Button statusSmallDeltaValueCheckBox;
81	private Button statusStatisticNoneRadioButton;
82	private Button statusStatisticErraticRadioButton;
83	private Button statusStatisticUnstableRadioButton;
84	private Text statusBuildsToConfirm;
85
86	// TODO See whether config descriptors need to be set as preferences or not...
87	// private Table configDescriptorsTable;
88
89	private BuildsView buildsView;
90
91/**
92 * Utility method that creates a push button instance and sets the default
93 * layout data.
94 *
95 * @param parent
96 *            the parent for the new button
97 * @param label
98 *            the label for the new button
99 * @return the newly-created button
100 */
101private Button createCheckBox(Composite parent, String label) {
102	Button button = new Button(parent, SWT.CHECK);
103	button.setText(label);
104	button.addSelectionListener(this);
105	GridData data = new GridData();
106	data.horizontalAlignment = GridData.FILL;
107	data.horizontalSpan = 5;
108	button.setLayoutData(data);
109	return button;
110}
111
112/**
113 * Create a text field specific for this application
114 *
115 * @param parent
116 *            the parent of the new text field
117 * @return the new text field
118 */
119private CCombo createCombo(Composite parent) {
120	CCombo combo= new CCombo(parent, SWT.BORDER);
121	combo.addModifyListener(this);
122	GridData data = new GridData();
123	data.horizontalSpan = 3;
124	data.horizontalAlignment = GridData.FILL;
125	data.grabExcessHorizontalSpace = true;
126	data.verticalAlignment = GridData.CENTER;
127	data.grabExcessVerticalSpace = false;
128	combo.setLayoutData(data);
129	return combo;
130}
131
132
133/**
134 * Creates composite control and sets the default layout data.
135 *
136 * @param parent
137 *            the parent of the new composite
138 * @param numColumns
139 *            the number of columns for the new composite
140 * @param hSpan TODO
141 * @return the newly-created coposite
142 */
143private Composite createComposite(Composite parent, int numColumns, int hSpan) {
144	Composite composite = new Composite(parent, SWT.NULL);
145
146	// GridLayout
147	GridLayout layout = new GridLayout();
148	layout.numColumns = numColumns;
149	composite.setLayout(layout);
150
151	// GridData
152	GridData data = new GridData();
153	data.verticalAlignment = GridData.FILL;
154	data.horizontalAlignment = GridData.FILL;
155	data.horizontalSpan = hSpan;
156	composite.setLayoutData(data);
157	return composite;
158}
159
160/**
161 * (non-Javadoc) Method declared on PreferencePage
162 */
163protected Control createContents(Composite parent) {
164
165	this.buildsView = (BuildsView) PerformancesView.getWorkbenchView("org.eclipse.test.internal.performance.results.ui.BuildsView");
166	if (this.buildsView == null) {
167		Label errorLabel = createLabel(parent, "No performances preferences can be set because the build view has not been created yet!", false);
168		errorLabel.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
169	} else {
170		// Eclipse version choice
171		Composite composite_eclipseVersion = createComposite(parent, 5, 1);
172		createLabel(composite_eclipseVersion, "Eclipse version", false);
173		Composite composite_versionChoice = createComposite(composite_eclipseVersion, 5, 1);
174		this.mVersionRadioButton = createRadioButton(composite_versionChoice, "v"+ECLIPSE_MAINTENANCE_VERSION);
175		this.dVersionRadionButton = createRadioButton(composite_versionChoice, "v"+ECLIPSE_DEVELOPMENT_VERSION);
176
177		// Database location
178		Composite compositeDatabase = createComposite(parent, 5, 1);
179		Group databaseGroup = createGroup(compositeDatabase, "Database", 5);
180		Composite compositeDatabaseConnection = createComposite(databaseGroup, 3, 5);
181		this.dbConnectionCheckBox = createCheckBox(compositeDatabaseConnection, "Connected");
182		this.dbRelengRadioButton = createRadioButton(compositeDatabaseConnection, "Releng");
183		this.dbLocalRadioButton = createRadioButton(compositeDatabaseConnection, "Local");
184		this.dbLocationLabel = createLabel(databaseGroup, "Location", false);
185		this.databaseLocationCombo = createCombo(databaseGroup);
186		this.databaseLocationCombo.setEditable(false);
187	    this.dbLocalBrowseButton = createPushButton(databaseGroup, "Browse");
188
189		// Status
190		Composite compositeStatus = createComposite(parent, 1, 3);
191		Group statusGroup = createGroup(compositeStatus, "Status", 1);
192		this.statusValuesCheckBox = createCheckBox(statusGroup, "Values");
193		this.statusValuesCheckBox.setToolTipText("Include numbers while writing status");
194		Group statusErrorGroup = createGroup(statusGroup, "Error level", 5);
195		statusErrorGroup.setToolTipText("Exclude from the written status failures depending on their build result error...");
196		this.statusErrorNoneRadioButton = createRadioButton(statusErrorGroup, "None");
197		this.statusErrorNoneRadioButton.setToolTipText("Do not exclude failures if they have a noticeable error");
198		this.statusErrorInvalidRadioButton = createRadioButton(statusErrorGroup, "Invalid");
199		this.statusErrorInvalidRadioButton.setToolTipText("Exclude all invalid failures (i.e. result error is over 100%)");
200		this.statusErrorWeirdRadioButton = createRadioButton(statusErrorGroup, "Weird");
201		this.statusErrorWeirdRadioButton.setToolTipText("Exclude all weird failures (i.e. result error is over 50%)");
202		this.statusErrorSuspiciousRadioButton = createRadioButton(statusErrorGroup, "Suspicious");
203		this.statusErrorSuspiciousRadioButton.setToolTipText("Exclude all suspicious failures (i.e. result error is over 25%)");
204		this.statusErrorNoticeableRadioButton = createRadioButton(statusErrorGroup, "Noticeable");
205		this.statusErrorNoticeableRadioButton.setToolTipText("Exclude all failures which have a noticeable error (i.e result error is over 3%)");
206		Group statusSmallGroup = createGroup(statusGroup, "Small value", 5);
207		statusErrorGroup.setToolTipText("Exclude from the written status failures depending on their value");
208		this.statusSmallBuildValueCheckBox = createCheckBox(statusSmallGroup, "Build value");
209		this.statusSmallBuildValueCheckBox.setToolTipText("Exclude all failures which have a build result value smaller than 100ms");
210		this.statusSmallDeltaValueCheckBox = createCheckBox(statusSmallGroup, "Delta value");
211		this.statusSmallDeltaValueCheckBox.setToolTipText("Exclude all failures which have a delta result value smaller than 100ms");
212		Group statusStatisticsGroup = createGroup(statusGroup, "Statistics", 5);
213		statusStatisticsGroup.setToolTipText("Exclude from the written status failures depending on build results statistics...");
214		this.statusStatisticNoneRadioButton = createRadioButton(statusStatisticsGroup, "None");
215		this.statusStatisticNoneRadioButton.setToolTipText("Do not exclude failures which have bad baseline results statistics (i.e. variation is over 10%)");
216		this.statusStatisticUnstableRadioButton = createRadioButton(statusStatisticsGroup, "Unstable");
217		this.statusStatisticUnstableRadioButton.setToolTipText("Exclude all failures which have unstable baseline results statistics (i.e. variation is between 10% and 20%)");
218		this.statusStatisticErraticRadioButton = createRadioButton(statusStatisticsGroup, "Erratic");
219		this.statusStatisticErraticRadioButton.setToolTipText("Exclude all failures which have erratic baseline results statistics (i.e. variation is over 20%)");
220		createLabel(statusGroup, "Builds to confirm:", false);
221		this.statusBuildsToConfirm = createTextField(statusGroup);
222		this.statusBuildsToConfirm.setToolTipText("The number of previous builds to take into account to confirm a regression");
223
224		// Milestones
225		Composite compositeMilestones = createComposite(parent, 3, 1);
226		createLabel(compositeMilestones, "Milestones", false);
227		this.milestonesCombo = createCombo(compositeMilestones);
228		this.milestonesCombo.setToolTipText("Enter the date of the milestone as yyyymmddHHMM");
229
230		// Last build
231		StringBuffer tooltip = new StringBuffer("Select the last build to display performance results\n");
232		tooltip.append("If set then performance results won't be displayed for any build after this date...");
233		String tooltipText = tooltip.toString();
234		Composite compositeLastBuild = createComposite(parent, 3, 1);
235	//	this.lastBuildCheckBox = createCheckBox(compositeLastBuild, "Until last build");
236		createLabel(compositeLastBuild, "Last build: ", false);
237		this.lastBuildCombo = createCombo(compositeLastBuild);
238		this.lastBuildCombo.setEditable(false);
239		this.lastBuildCombo.setToolTipText(tooltipText);
240		this.lastBuildCombo.add("");
241		initBuildsList();
242
243		// Default dimension layout
244		tooltip = new StringBuffer("Select the default dimension which will be used for performance results\n");
245		tooltip.append("When changed, the new selected dimension is automatically added to the dimensions list below...");
246		tooltipText = tooltip.toString();
247		Composite compositeDefaultDimension = createComposite(parent, 3, 1);
248		createLabel(compositeDefaultDimension, "Default dimension: ", false);
249		this.defaultDimensionCombo = createCombo(compositeDefaultDimension);
250		this.defaultDimensionCombo.setEditable(false);
251		this.defaultDimensionCombo.setToolTipText(tooltipText);
252
253		// Results dimensions layout
254		tooltip = new StringBuffer("Select the dimensions which will be used while generating performance results\n");
255		tooltip.append("When changed, the default dimension above is automatically added to the new list...");
256		tooltipText = tooltip.toString();
257		Composite compositeResultsDimensions = createComposite(parent, 3, 1);
258		createLabel(compositeResultsDimensions, "Results dimensions: ", true/*beginning*/);
259		this.resultsDimensionsList = createList(compositeResultsDimensions);
260		this.resultsDimensionsList.setToolTipText(tooltipText);
261
262		// Config descriptors layout
263		/* TODO See whether config descriptors need to be set as preferences or not...
264		Composite compositeConfigDescriptors = createComposite(parent, 3);
265		createLabel(compositeConfigDescriptors, "Config descriptors: ", false);
266		this.configDescriptorsTable = createTable(compositeConfigDescriptors);
267		TableColumn firstColumn = new TableColumn(this.configDescriptorsTable, SWT.LEFT);
268		firstColumn.setText ("Name");
269		firstColumn.setWidth(50);
270		TableColumn secondColumn = new TableColumn(this.configDescriptorsTable, SWT.FILL | SWT.LEFT);
271		secondColumn.setText ("Description");
272		secondColumn.setWidth(300);
273		*/
274
275		// init values
276		initializeValues();
277	}
278
279	// font = null;
280	Composite contents = new Composite(parent, SWT.NULL);
281	contents.pack(true);
282	return contents;
283}
284
285/**
286 * Utility method that creates a label instance and sets the default layout
287 * data.
288 *
289 * @param parent
290 *            the parent for the new label
291 * @param text
292 *            the text for the new label
293 * @return the new label
294 */
295private Group createGroup(Composite parent, String text, int columns) {
296	Group group = new Group(parent, SWT.NONE);
297	group.setLayout(new GridLayout(columns, false));
298	group.setText(text);
299	GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
300//	data.horizontalSpan = 1;
301	group.setLayoutData(data);
302	return group;
303}
304
305/**
306 * Utility method that creates a label instance and sets the default layout
307 * data.
308 *
309 * @param parent
310 *            the parent for the new label
311 * @param text
312 *            the text for the new label
313 * @param beginning TODO
314 * @return the new label
315 */
316private Label createLabel(Composite parent, String text, boolean beginning) {
317	Label label = new Label(parent, SWT.BEGINNING|SWT.LEFT);
318	label.setText(text);
319	GridData data = new GridData();
320	data.horizontalAlignment = GridData.FILL;
321	data.verticalAlignment = beginning ? GridData.BEGINNING : GridData.CENTER;
322	label.setLayoutData(data);
323	return label;
324}
325
326/**
327 * Create a text field specific for this application
328 *
329 * @param parent
330 *            the parent of the new text field
331 * @return the new text field
332 */
333private List createList(Composite parent) {
334	List list = new List(parent, SWT.MULTI | SWT.BORDER);
335	list.addSelectionListener(this);
336	GridData data = new GridData();
337	data.horizontalSpan = 2;
338	data.horizontalAlignment = GridData.FILL;
339	data.grabExcessHorizontalSpace = true;
340	data.verticalAlignment = GridData.CENTER;
341	data.grabExcessVerticalSpace = false;
342	list.setLayoutData(data);
343	return list;
344}
345
346/**
347 * Utility method that creates a push button instance and sets the default
348 * layout data.
349 *
350 * @param parent
351 *            the parent for the new button
352 * @param label
353 *            the label for the new button
354 * @return the newly-created button
355 */
356private Button createPushButton(Composite parent, String label) {
357	Button button = new Button(parent, SWT.PUSH);
358	button.setText(label);
359	button.addSelectionListener(this);
360	GridData data = new GridData();
361	data.horizontalAlignment = SWT.LEFT;
362	data.grabExcessHorizontalSpace = true;
363//	data.horizontalSpan = 2;
364	data.minimumWidth = 100;
365	button.setLayoutData(data);
366	return button;
367}
368
369/**
370 * Utility method that creates a radio button instance and sets the default
371 * layout data.
372 *
373 * @param parent
374 *            the parent for the new button
375 * @param label
376 *            the label for the new button
377 * @return the newly-created button
378 */
379private Button createRadioButton(Composite parent, String label) {
380	Button button = new Button(parent, SWT.RADIO | SWT.LEFT);
381	button.setText(label);
382	button.addSelectionListener(this);
383	GridData data = new GridData();
384	button.setLayoutData(data);
385	return button;
386}
387
388/*
389 * Create a text field specific for this application
390 *
391 * @param parent
392 *            the parent of the new text field
393 * @return the new text field
394 *
395private Table createTable(Composite parent) {
396	Table table = new Table(parent, SWT.BORDER);
397	table.setLinesVisible (true);
398	table.setHeaderVisible (true);
399	GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1);
400	gridData.heightHint = 150;
401	table.setLayoutData(gridData);
402	return table;
403}
404*/
405
406/*
407 * Create a text field specific for this application
408 *
409 * @param parent
410 *            the parent of the new text field
411 * @return the new text field
412 */
413private Text createTextField(Composite parent) {
414	Text text = new Text(parent, SWT.SINGLE | SWT.BORDER);
415	text.addModifyListener(this);
416	GridData data = new GridData();
417	data.horizontalAlignment = GridData.FILL;
418	data.grabExcessHorizontalSpace = true;
419	data.verticalAlignment = GridData.CENTER;
420	data.grabExcessVerticalSpace = false;
421	text.setLayoutData(data);
422	return text;
423}
424
425/**
426 * The <code>ReadmePreferencePage</code> implementation of this
427 * <code>PreferencePage</code> method returns preference store that belongs to
428 * the our plugin. This is important because we want to store our preferences
429 * separately from the workbench.
430 */
431protected IPreferenceStore doGetPreferenceStore() {
432	return UiPlugin.getDefault().getPreferenceStore();
433}
434
435/**
436 * @return The dialog title
437 */
438String getDialogTitle() {
439	String title = DB_Results.getDbTitle();
440	if (title == null) {
441		// DB is not connected
442		int version;
443		if (this.mVersionRadioButton.getSelection()) {
444			version = ECLIPSE_MAINTENANCE_VERSION;
445		} else {
446			version = ECLIPSE_DEVELOPMENT_VERSION;
447		}
448		title = "Eclipse " + version + " - DB not connected";
449	}
450	return title;
451}
452
453/*
454 * Get the directory path using the given location as default.
455 */
456private String getDirectoryPath(String location) {
457	DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.OPEN);
458	dialog.setText(getDialogTitle());
459	dialog.setMessage("Select local database directory:");
460	dialog.setFilterPath(location);
461	String path = dialog.open();
462	if (path != null) {
463		File dir = new File(path);
464		if (dir.exists() && dir.isDirectory()) {
465			return dir.getAbsolutePath();
466		}
467	}
468	return null;
469}
470
471/*
472 * (non-Javadoc) Method declared on IWorkbenchPreferencePage
473 */
474public void init(IWorkbench workbench) {
475	// do nothing
476}
477
478/*
479 * Init he contents of the dimensions list controls.
480 */
481void initDimensionsLists() {
482	// Dimensions lists
483	java.util.List dimensions = PerformanceTestPlugin.getDimensions();
484	Iterator names = dimensions.iterator();
485	while (names.hasNext()) {
486		String name = (String) names.next();
487		this.defaultDimensionCombo.add(name);
488		this.resultsDimensionsList.add(name);
489	}
490}
491
492/*
493 * Init he contents of the dimensions list controls.
494 */
495private void initBuildsList() {
496	String[] builds = DB_Results.getBuilds();
497	Arrays.sort(builds, Util.BUILD_DATE_COMPARATOR);
498	int length = builds.length;
499	for (int i=length-1; i>=0; i--) {
500		this.lastBuildCombo.add(builds[i]);
501	}
502}
503
504/**
505 * Initializes states of the controls using default values in the preference
506 * store.
507 */
508private void initializeDefaults() {
509	IPreferenceStore store = getPreferenceStore();
510
511	// Init default database values
512	this.dbConnectionCheckBox.setSelection(store.getDefaultBoolean(PRE_DATABASE_CONNECTION));
513	this.dbRelengRadioButton.setSelection(false);
514	this.dbLocalRadioButton.setSelection(false);
515	final boolean dbLocal = store.getDefaultBoolean(PRE_DATABASE_LOCAL);
516	if (dbLocal) {
517		this.dbLocalRadioButton.setSelection(true);
518	} else {
519		this.dbRelengRadioButton.setSelection(true);
520	}
521	this.databaseLocationCombo.removeAll();
522	this.databaseLocationCombo.setText(store.getDefaultString(PRE_DATABASE_LOCATION));
523	updateDatabaseGroup();
524
525	// Init default status values
526	int writeStatus = store.getDefaultInt(PRE_WRITE_STATUS);
527	initStatusValues(writeStatus);
528
529	// Init eclipse version
530	this.mVersionRadioButton.setSelection(false);
531	this.dVersionRadionButton.setSelection(false);
532	int version = store.getDefaultInt(PRE_ECLIPSE_VERSION);
533	if (version == ECLIPSE_MAINTENANCE_VERSION) {
534		this.mVersionRadioButton.setSelection(true);
535	} else {
536		this.dVersionRadionButton.setSelection(true);
537	}
538    updateBrowseButtonToolTip(version);
539
540	// Milestones
541	this.milestonesCombo.removeAll();
542	String prefix = PRE_MILESTONE_BUILDS + "." + version;
543	String milestone = store.getDefaultString(prefix + "0");
544	int index = 0;
545	while (milestone != null && milestone.length() > 0) {
546		this.milestonesCombo.add(milestone);
547		milestone = store.getDefaultString(prefix + ++index);
548	}
549
550	// Init last build
551	String lastBuild = store.getDefaultString(PRE_LAST_BUILD);
552//	if (lastBuild.length() == 0) {
553//		this.lastBuildCheckBox.setSelection(false);
554//		this.lastBuildCombo.setEnabled(false);
555//	} else {
556//		this.lastBuildCombo.setEnabled(true);
557//	}
558	this.lastBuildCombo.setText(lastBuild);
559
560	// Init default default dimension
561	String defaultDimension = store.getDefaultString(PRE_DEFAULT_DIMENSION);
562	this.defaultDimensionCombo.setText(defaultDimension);
563
564	// Init default generated dimensions
565	this.resultsDimensionsList.add(store.getDefaultString(PRE_RESULTS_DIMENSION+".0"));
566	this.resultsDimensionsList.add(store.getDefaultString(PRE_RESULTS_DIMENSION+".1"));
567}
568
569/**
570 * Initializes states of the controls from the preference store.
571 */
572private void initializeValues() {
573	IPreferenceStore store = getPreferenceStore();
574
575	// Init database info
576	this.dbConnectionCheckBox.setSelection(store.getBoolean(PRE_DATABASE_CONNECTION));
577	final boolean dbLocal = store.getBoolean(PRE_DATABASE_LOCAL);
578	if (dbLocal) {
579		this.dbLocalRadioButton.setSelection(true);
580		this.dbRelengRadioButton.setToolTipText("");
581	} else {
582		this.dbRelengRadioButton.setSelection(true);
583		this.dbRelengRadioButton.setToolTipText(NETWORK_DATABASE_LOCATION);
584	}
585	this.databaseLocationCombo.removeAll();
586	this.databaseLocationCombo.setText(store.getString(PRE_DATABASE_LOCATION));
587	for (int i = 0; i < 3; i++) {
588		String history = store.getString(PRE_DATABASE_LOCATION + "." + i);
589		if (history.length() == 0)
590			break;
591		this.databaseLocationCombo.add(history);
592	}
593	updateDatabaseGroup();
594
595	// Init status values
596	int writeStatus = store.getInt(PRE_WRITE_STATUS);
597	initStatusValues(writeStatus);
598
599	// Init eclipse version
600	int version = store.getInt(PRE_ECLIPSE_VERSION);
601	if (version == ECLIPSE_MAINTENANCE_VERSION) {
602		this.mVersionRadioButton.setSelection(true);
603	} else {
604		this.dVersionRadionButton.setSelection(true);
605	}
606    updateBrowseButtonToolTip(version);
607
608	// Milestones
609	String prefix = PRE_MILESTONE_BUILDS + "." + version;
610	int index = 0;
611	String milestone = store.getString(prefix + index);
612	while (milestone != null && milestone.length() > 0) {
613		this.milestonesCombo.add(milestone);
614		milestone = store.getString(prefix + ++index);
615	}
616
617	// Init last build
618	String lastBuild = store.getString(PRE_LAST_BUILD);
619//	if (lastBuild.length() == 0) {
620//		this.lastBuildCheckBox.setSelection(false);
621//		this.lastBuildCombo.setEnabled(false);
622//	} else {
623//		this.lastBuildCombo.setEnabled(true);
624//	}
625	this.lastBuildCombo.setText(lastBuild);
626
627	// Init composite lists
628	initDimensionsLists();
629
630	// Init default dimension
631	String defaultDimension = store.getString(PRE_DEFAULT_DIMENSION);
632	this.defaultDimensionCombo.setText(defaultDimension);
633
634	// Init generated dimensions
635	int count = this.resultsDimensionsList.getItemCount();
636	int[] indices = new int[count];
637	int n = 0;
638	String resultsDimension = store.getString(PRE_RESULTS_DIMENSION + "." + n);
639	while (resultsDimension.length() > 0) {
640		indices[n++] = this.resultsDimensionsList.indexOf(resultsDimension);
641		resultsDimension = store.getString(PRE_RESULTS_DIMENSION + "." + n);
642	}
643	if (n < count) {
644		System.arraycopy(indices, 0, indices = new int[n], 0, n);
645	}
646	this.resultsDimensionsList.select(indices);
647
648	// Init config descriptors
649	/* TODO See whether config descriptors need to be set as preferences or not...
650	this.configDescriptorsTable.clearAll();
651	int d = 0;
652	String descriptorName = store.getString(PRE_CONFIG_DESCRIPTOR_NAME + "." + d);
653	String descriptorDescription = store.getString(PRE_CONFIG_DESCRIPTOR_DESCRIPTION + "." + d++);
654	while (descriptorName.length() > 0) {
655		TableItem tableItem = new TableItem (this.configDescriptorsTable, SWT.NONE);
656		tableItem.setText (0, descriptorName);
657		tableItem.setText (1, descriptorDescription);
658		descriptorName = store.getString(PRE_CONFIG_DESCRIPTOR_NAME + "." + d);
659		descriptorDescription = store.getString(PRE_CONFIG_DESCRIPTOR_DESCRIPTION + "." + d++);
660	}
661	*/
662}
663
664/**
665 * @param writeStatus The observed status to write
666 */
667private void initStatusValues(int writeStatus) {
668	this.statusValuesCheckBox.setSelection((writeStatus & STATUS_VALUES) != 0);
669	this.statusErrorNoneRadioButton.setSelection(false);
670	this.statusErrorNoticeableRadioButton.setSelection(false);
671	this.statusErrorSuspiciousRadioButton.setSelection(false);
672	this.statusErrorWeirdRadioButton.setSelection(false);
673	this.statusErrorInvalidRadioButton.setSelection(false);
674	switch (writeStatus & STATUS_ERROR_LEVEL_MASK) {
675		case STATUS_ERROR_NONE:
676			this.statusErrorNoneRadioButton.setSelection(true);
677			break;
678		case STATUS_ERROR_NOTICEABLE:
679			this.statusErrorNoticeableRadioButton.setSelection(true);
680			break;
681		case STATUS_ERROR_SUSPICIOUS:
682			this.statusErrorSuspiciousRadioButton.setSelection(true);
683			break;
684		case STATUS_ERROR_WEIRD:
685			this.statusErrorWeirdRadioButton.setSelection(true);
686			break;
687		case STATUS_ERROR_INVALID:
688			this.statusErrorInvalidRadioButton.setSelection(true);
689			break;
690	}
691	this.statusSmallBuildValueCheckBox.setSelection(false);
692	this.statusSmallDeltaValueCheckBox.setSelection(false);
693	switch (writeStatus & STATUS_SMALL_VALUE_MASK) {
694		case STATUS_SMALL_VALUE_BUILD:
695			this.statusSmallBuildValueCheckBox.setSelection(true);
696			break;
697		case STATUS_SMALL_VALUE_DELTA:
698			this.statusSmallDeltaValueCheckBox.setSelection(true);
699			break;
700	}
701	this.statusStatisticNoneRadioButton.setSelection(false);
702	this.statusStatisticErraticRadioButton.setSelection(false);
703	this.statusStatisticUnstableRadioButton.setSelection(false);
704	switch (writeStatus & STATUS_STATISTICS_MASK) {
705		case 0:
706			this.statusStatisticNoneRadioButton.setSelection(true);
707			break;
708		case STATUS_STATISTICS_ERRATIC:
709			this.statusStatisticErraticRadioButton.setSelection(true);
710			break;
711		case STATUS_STATISTICS_UNSTABLE:
712			this.statusStatisticUnstableRadioButton.setSelection(true);
713			break;
714	}
715	this.statusBuildsToConfirm.setText(String.valueOf(writeStatus & STATUS_BUILDS_NUMBER_MASK));
716}
717
718/**
719 * (non-Javadoc) Method declared on ModifyListener
720 */
721public void modifyText(ModifyEvent event) {
722
723	// Add default dimension to results if necessary
724	if (event.getSource() == this.defaultDimensionCombo) {
725		String[] resultsDimensions = this.resultsDimensionsList.getSelection();
726		int length = resultsDimensions.length;
727		String defaultDimension = this.defaultDimensionCombo.getText();
728		for (int i = 0; i < length; i++) {
729			if (resultsDimensions[i].equals(defaultDimension)) {
730				// Default dim is already set as a results dimension, hence nothing has to be done
731				return;
732			}
733		}
734		System.arraycopy(resultsDimensions, 0, resultsDimensions = new String[length + 1], 0, length);
735		resultsDimensions[length] = defaultDimension;
736		this.resultsDimensionsList.setSelection(resultsDimensions);
737	}
738
739	// Add default dimension to results if necessary
740	if (event.getSource() == this.milestonesCombo) {
741
742		// Verify the only digits are entered
743		String milestoneDate = this.milestonesCombo.getText();
744		final int mLength = milestoneDate.length();
745		if (mLength > 0) {
746			for (int i=0; i<mLength; i++) {
747				if (!Character.isDigit(milestoneDate.charAt(i))) {
748					String[] items = this.milestonesCombo.getItems();
749					int length = items.length;
750					for (int j=0; j<length; j++) {
751						if (items[j].equals(milestoneDate)) {
752							// already existing milestone, leave silently
753							if (MessageDialog.openQuestion(getShell(), getDialogTitle(), "Do you want to select milestone "+milestoneDate+" as the last build?")) {
754								String builds[] = this.lastBuildCombo.getItems();
755								int bLength = builds.length;
756								String milestone = milestoneDate.substring(milestoneDate.indexOf('-')+1);
757								for (int b=0; b<bLength; b++) {
758									if (builds[b].length() > 0 && Util.getBuildDate(builds[b]).equals(milestone)) {
759										this.lastBuildCombo.select(b);
760										break;
761									}
762								}
763							}
764							return;
765						}
766					}
767					openMilestoneErrorMessage(milestoneDate);
768					return;
769				}
770			}
771		}
772
773		// Do not verify further until a complete milestone date is entered
774		if (mLength < 12) return;
775
776		// Verify the digits
777		try {
778			String str = milestoneDate.substring(0, 4);
779			int year = Integer.parseInt(str);
780			if (year < 2009 || year > 2020) { // 2020 should be enough!
781				MessageDialog.openError(getShell(), getDialogTitle(), milestoneDate+": "+str+" is an invalid year, only value between 2009 and 2020 is accepted!");
782				return;
783			}
784			str = milestoneDate.substring(4, 6);
785			int month = Integer.parseInt(str);
786			if (month <= 0 || month > 12) {
787				MessageDialog.openError(getShell(), getDialogTitle(), milestoneDate+": "+str+" is an invalid month, it should be only from 01 to 12!");
788				return;
789			}
790			str = milestoneDate.substring(6, 8);
791			int day = Integer.parseInt(str);
792			if (day <= 0 || day > 31) {
793				// TODO improve this verification
794				MessageDialog.openError(getShell(), getDialogTitle(), milestoneDate+": "+str+" is an invalid day, it should be only from 01 to 31!");
795				return;
796			}
797			str = milestoneDate.substring(8, 10);
798			int hour = Integer.parseInt(str);
799			if (hour < 0 || hour > 23) {
800				MessageDialog.openError(getShell(), getDialogTitle(), milestoneDate+": "+str+" is an invalid hour, it should be only from 00 to 23!");
801				return;
802			}
803			str = milestoneDate.substring(10, 12);
804			int min = Integer.parseInt(str);
805			if (min < 0 || min > 59) {
806				MessageDialog.openError(getShell(), getDialogTitle(), milestoneDate+": "+str+" is invalid minutes, it should be only from 00 to 59!");
807				return;
808			}
809		}
810		catch (NumberFormatException nfe) {
811			openMilestoneErrorMessage(milestoneDate);
812		}
813
814		// Get combo info
815		String[] milestones = this.milestonesCombo.getItems();
816		int length = milestones.length;
817		String lastMilestone = length == 0 ? null : milestones[length-1];
818
819		// Verify that the added milestone is valid
820		final String databaseLocation = this.databaseLocationCombo.getText();
821		char version = databaseLocation.charAt(databaseLocation.length()-1);
822
823		// Verify that the milestone follow the last one
824		String milestoneName;
825		if (lastMilestone == null) {
826			// No previous last milestone
827			milestoneName = "M1";
828		} else {
829			// Compare with last milestone
830			if (lastMilestone.charAt(0) == 'M') {
831				char digit = lastMilestone.charAt(1);
832				if (digit == '6') {
833					// M6 is the last dvpt milestone
834					milestoneName = "RC1";
835				} else {
836					milestoneName = "M" +((char)(digit+1));
837				}
838			} else if (lastMilestone.startsWith("RC")) {
839				char digit = lastMilestone.charAt(2);
840				if (digit == '4') {
841					// RC4 is the last release candidate milestone
842					milestoneName = "R3_"+version;
843				} else {
844					milestoneName = "RC" +((char)(digit+1));
845				}
846			} else if (lastMilestone.startsWith("R3_"+version+"-")) {
847				milestoneName = "R3_" + version + "_1";
848			} else if (lastMilestone.startsWith("R3_"+version+"_")) {
849				char digit = lastMilestone.charAt(5);
850				milestoneName = "R3_" + version + "_" + ((char)(digit+1));
851			} else {
852				MessageDialog.openError(getShell(), getDialogTitle(), "Unexpected last milestone name: "+lastMilestone+"!");
853				return;
854			}
855
856			// Verify the date of the new milestone
857			int lastMilestoneDash = lastMilestone.indexOf('-');
858			final String lastMilestoneDate = lastMilestone.substring(lastMilestoneDash+1);
859			if (milestoneDate.compareTo(lastMilestoneDate) <= 0) {
860				// TODO improve this verification
861				MessageDialog.openError(getShell(), getDialogTitle(), "Milestone "+milestoneDate+" should be after the last milestone: "+lastMilestoneDate+"!");
862				return;
863			}
864		}
865
866		// Verification are ok, ask to add the milestone
867		final String milestone = milestoneName + "-" + milestoneDate;
868		if (MessageDialog.openConfirm(getShell(), getDialogTitle(), milestoneDate+" is a valid milestone date.\n\nDo you want to add the milestone '"+milestone+"' to the preferences?")) {
869			this.milestonesCombo.add(milestone);
870			this.milestonesCombo.setText("");
871		}
872	}
873
874	// Verify the 'builds to confirm' number
875	if (event.getSource() == this.statusBuildsToConfirm) {
876		try {
877			int number = Integer.parseInt(this.statusBuildsToConfirm.getText());
878			if (number < 1 ) {
879				this.statusBuildsToConfirm.setText("1");
880			} else {
881				int buildsNumber = DB_Results.getBuildsNumber();
882				if (number > buildsNumber) {
883					this.statusBuildsToConfirm.setText(String.valueOf(buildsNumber));
884				}
885			}
886		}
887		catch (NumberFormatException nfe) {
888			this.statusBuildsToConfirm.setText("1");
889		}
890	}
891}
892
893
894/**
895 * @param milestone
896 */
897void openMilestoneErrorMessage(String milestone) {
898	MessageDialog.openError(getShell(), getDialogTitle(), milestone+" is an invalid milestone date. Only 'yyyymmddHHMM' format is accepted!");
899}
900
901/*
902 * (non-Javadoc) Method declared on PreferencePage
903 */
904protected void performDefaults() {
905	super.performDefaults();
906	initializeDefaults();
907}
908
909/*
910 * (non-Javadoc) Method declared on PreferencePage
911 */
912public boolean performOk() {
913	final boolean hasBuildsView = this.buildsView != null;
914	if (hasBuildsView) {
915		storeValues();
916		try {
917			IEclipsePreferences preferences = new InstanceScope().getNode(PLUGIN_ID);
918			preferences.flush();
919			this.buildsView.resetView();
920		} catch (BackingStoreException e) {
921			e.printStackTrace();
922			return false;
923		}
924	}
925	return true;
926}
927
928/**
929 * Stores the values of the controls back to the preference store.
930 */
931private void storeValues() {
932	IPreferenceStore store = getPreferenceStore();
933
934	// Set version
935	int version;
936	if (this.mVersionRadioButton.getSelection()) {
937		version = ECLIPSE_MAINTENANCE_VERSION;
938	} else {
939		version = ECLIPSE_DEVELOPMENT_VERSION;
940	}
941	store.setValue(PRE_ECLIPSE_VERSION, version);
942
943	// Set database values
944	store.setValue(PRE_DATABASE_CONNECTION, this.dbConnectionCheckBox.getSelection());
945	final boolean dbLocal = this.dbLocalRadioButton.getSelection();
946	store.setValue(PRE_DATABASE_LOCAL, dbLocal);
947	String location = this.databaseLocationCombo.getText();
948	if (dbLocal) {
949		store.setValue(PRE_DATABASE_LOCATION, location);
950	} else {
951		store.setValue(PRE_DATABASE_LOCATION, NETWORK_DATABASE_LOCATION);
952	}
953	int count = this.databaseLocationCombo.getItemCount();
954	for (int i=0; i<count; i++) {
955		String item = this.databaseLocationCombo.getItem(i);
956		if (item.equals(location)) {
957			this.databaseLocationCombo.remove(i);
958			break;
959		}
960	}
961	if (dbLocal) {
962		this.databaseLocationCombo.add(location, 0);
963	}
964	int i=0;
965	for (; i<count; i++) {
966		String item = this.databaseLocationCombo.getItem(i);
967		if (item.length() == 0) break;
968		store.setValue(PRE_DATABASE_LOCATION+"."+i, item);
969	}
970	while (store.getString(PRE_DATABASE_LOCATION+"."+i).length() > 0) {
971		store.setToDefault(PRE_DATABASE_LOCATION+"."+i);
972		i++;
973	}
974
975	// Set status values
976	int writeStatus = 0;
977	if (this.statusValuesCheckBox.getSelection()) {
978		writeStatus |= STATUS_VALUES;
979	}
980	if (this.statusErrorNoneRadioButton.getSelection()) {
981		writeStatus |= STATUS_ERROR_NONE;
982	} else if (this.statusErrorNoticeableRadioButton.getSelection()) {
983		writeStatus |= STATUS_ERROR_NOTICEABLE;
984	} else if (this.statusErrorSuspiciousRadioButton.getSelection()) {
985		writeStatus |= STATUS_ERROR_SUSPICIOUS;
986	} else if (this.statusErrorWeirdRadioButton.getSelection()) {
987		writeStatus |= STATUS_ERROR_WEIRD;
988	} else if (this.statusErrorInvalidRadioButton.getSelection()) {
989		writeStatus |= STATUS_ERROR_INVALID;
990	}
991	if (this.statusSmallBuildValueCheckBox.getSelection()) {
992		writeStatus |= STATUS_SMALL_VALUE_BUILD;
993	}
994	if (this.statusSmallDeltaValueCheckBox.getSelection()) {
995		writeStatus |= STATUS_SMALL_VALUE_DELTA;
996	}
997	if (this.statusStatisticNoneRadioButton.getSelection()) {
998		writeStatus &= ~STATUS_STATISTICS_MASK;
999	} else if (this.statusStatisticErraticRadioButton.getSelection()) {
1000		writeStatus |= STATUS_STATISTICS_ERRATIC;
1001	} else if (this.statusStatisticUnstableRadioButton.getSelection()) {
1002		writeStatus |= STATUS_STATISTICS_UNSTABLE;
1003	}
1004	writeStatus += Integer.parseInt(this.statusBuildsToConfirm.getText());
1005	store.setValue(PRE_WRITE_STATUS, writeStatus);
1006
1007	// Set milestones
1008	String prefix = PRE_MILESTONE_BUILDS + "." + version;
1009	count  = this.milestonesCombo.getItemCount();
1010	for (i=0; i<count; i++) {
1011		store.putValue(prefix + i, this.milestonesCombo.getItem(i));
1012	}
1013	Util.setMilestones(this.milestonesCombo.getItems());
1014
1015	// Unset previous additional milestones
1016	String milestone = store.getString(prefix + count);
1017	while (milestone != null && milestone.length() > 0) {
1018		store.putValue(prefix + count++, "");
1019		milestone = store.getString(prefix + count);
1020	}
1021
1022	// Set last build
1023	String lastBuild = this.lastBuildCombo.getText();
1024	store.putValue(PRE_LAST_BUILD, lastBuild);
1025
1026	// Set default dimension
1027	String defaultDimension = this.defaultDimensionCombo.getText();
1028	store.putValue(PRE_DEFAULT_DIMENSION, defaultDimension);
1029	DB_Results.setDefaultDimension(defaultDimension);
1030
1031	// Set generated dimensions
1032	int[] indices = this.resultsDimensionsList.getSelectionIndices();
1033	int length = indices.length;
1034	String[] dimensions = new String[length];
1035	if (length > 0) {
1036		for (i = 0; i < indices.length; i++) {
1037			dimensions[i] = this.resultsDimensionsList.getItem(indices[i]);
1038			store.putValue(PRE_RESULTS_DIMENSION + "." + i, dimensions[i]);
1039		}
1040	}
1041	int currentLength = DB_Results.getResultsDimensions().length;
1042	if (currentLength > length) {
1043		for (i = currentLength - 1; i >= length; i--) {
1044			store.putValue(PRE_RESULTS_DIMENSION + "." + i, ""); // reset extra dimensions
1045		}
1046	}
1047	DB_Results.setResultsDimensions(dimensions);
1048
1049	// Set config descriptors
1050	/* TODO See whether config descriptors need to be set as preferences or not...
1051	TableItem[] items = this.configDescriptorsTable.getItems();
1052	length = items.length;
1053	for (int i = 0; i < length; i++) {
1054		TableItem item = items[i];
1055		store.putValue(PRE_CONFIG_DESCRIPTOR_NAME + "." + i, item.getText(0));
1056		store.putValue(PRE_CONFIG_DESCRIPTOR_DESCRIPTION + "." + i, item.getText(1));
1057	}
1058	*/
1059}
1060
1061/**
1062 * (non-Javadoc) Method declared on SelectionListener
1063 */
1064public void widgetDefaultSelected(SelectionEvent event) {
1065}
1066
1067/**
1068 * (non-Javadoc) Method declared on SelectionListener
1069 */
1070public void widgetSelected(SelectionEvent event) {
1071
1072	// As for directory when 'Local' button is pushed
1073	final Object source = event.getSource();
1074	if (source == this.dbLocalBrowseButton) {
1075		String location = this.databaseLocationCombo.getText();
1076		String path = getDirectoryPath(location);
1077		if (path != null) {
1078			// First verify that the selected dir was correct
1079			int version;
1080			if (this.mVersionRadioButton.getSelection()) {
1081				version = ECLIPSE_MAINTENANCE_VERSION;
1082			} else {
1083				version = ECLIPSE_DEVELOPMENT_VERSION;
1084			}
1085			File dbDir = new File(path, "perfDb"+version);
1086			if (!dbDir.exists() || !dbDir.isDirectory()) {
1087				StringBuffer message = new StringBuffer("Invalid performance database directory\n");
1088				message.append(path+" should contain 'perfDb");
1089				message.append(version);
1090				message.append("' directory and none was found!");
1091				MessageDialog.openError(getShell(), getDialogTitle(), message.toString());
1092				return;
1093			}
1094
1095			// Look for selected dir in combo box list
1096			int count = this.databaseLocationCombo.getItemCount();
1097			int index = -1;
1098			for (int i = 0; i < count; i++) {
1099				String item = this.databaseLocationCombo.getItem(i);
1100				if (item.length() == 0) { // nothing in the combo-box list
1101					break;
1102				}
1103				if (item.equals(path)) {
1104					index = i;
1105					break;
1106				}
1107			}
1108			// Set the selected dir the more recent in the previous dirs list
1109			if (index !=  0) {
1110				if (index > 0) {
1111					// the dir was used before, but not recently => remove it from previous dirs list
1112					this.databaseLocationCombo.remove(index);
1113				}
1114				// add the selected dir on the top of the previous dirs list
1115				this.databaseLocationCombo.add(path, 0);
1116			}
1117			// Set combo box text
1118			this.databaseLocationCombo.setText(path);
1119			updateLocalDb();
1120		}
1121	}
1122
1123	// Reset dabase location when 'Releng' button is pushed
1124	if (source == this.dbConnectionCheckBox) {
1125		updateDatabaseGroup();
1126	}
1127
1128	// Reset dabase location when 'Releng' check-box is checked
1129	if (source == this.dbLocalRadioButton) {
1130		updateLocalDb();
1131	}
1132
1133	// Add default dimension to results if necessary
1134	if (source == this.resultsDimensionsList) {
1135		String[] resultsDimensions = this.resultsDimensionsList.getSelection();
1136		int length = resultsDimensions.length;
1137		String defaultDimension = this.defaultDimensionCombo.getText();
1138		for (int i = 0; i < length; i++) {
1139			if (resultsDimensions[i].equals(defaultDimension)) {
1140				// Default dim is already set as a results dimension, hence nothing has to be done
1141				return;
1142			}
1143		}
1144		System.arraycopy(resultsDimensions, 0, resultsDimensions = new String[length + 1], 0, length);
1145		resultsDimensions[length] = defaultDimension;
1146		this.resultsDimensionsList.setSelection(resultsDimensions);
1147	}
1148
1149//	if (source == this.lastBuildCheckBox) {
1150//		this.lastBuildCombo.setEnabled(this.lastBuildCheckBox.getSelection());
1151//	}
1152
1153	if (source == this.mVersionRadioButton) {
1154		if (this.mVersionRadioButton.getSelection()) {
1155		    updateBrowseButtonToolTip(ECLIPSE_MAINTENANCE_VERSION);
1156		}
1157	}
1158
1159	if (source == this.dVersionRadionButton) {
1160		if (this.dVersionRadionButton.getSelection()) {
1161		    updateBrowseButtonToolTip(ECLIPSE_DEVELOPMENT_VERSION);
1162		}
1163	}
1164}
1165
1166/*
1167 * Update browse tooltip
1168 */
1169void updateBrowseButtonToolTip(int version) {
1170	this.dbLocalBrowseButton.setToolTipText("Select the directory where the database was unzipped\n(i.e. should contain the perfDb"+version+" subdirectory)");
1171}
1172
1173/*
1174 * Update database group controls.
1175 */
1176void updateDatabaseGroup() {
1177	if (this.dbConnectionCheckBox.getSelection()) {
1178		this.dbRelengRadioButton.setEnabled(true);
1179		this.dbLocalRadioButton.setEnabled(true);
1180		updateLocalDb();
1181	} else {
1182		this.dbRelengRadioButton.setEnabled(false);
1183		this.dbLocalRadioButton.setEnabled(false);
1184		this.databaseLocationCombo.setEnabled(false);
1185		this.dbLocalBrowseButton.setEnabled(false);
1186		setValid(true);
1187	}
1188}
1189
1190/*
1191 * Update database location controls.
1192 */
1193void updateLocalDb() {
1194	if (this.dbLocalRadioButton.getSelection()) {
1195		this.databaseLocationCombo.setEnabled(true);
1196		this.dbLocalBrowseButton.setEnabled(true);
1197		if (this.databaseLocationCombo.getItemCount() == 0) {
1198			this.databaseLocationCombo.setText("");
1199			setValid(false);
1200		} else {
1201			this.databaseLocationCombo.select(0);
1202			setValid(true);
1203		}
1204		this.dbRelengRadioButton.setToolTipText("");
1205		this.dbLocationLabel.setEnabled(true);
1206	} else {
1207		this.dbRelengRadioButton.setToolTipText(NETWORK_DATABASE_LOCATION);
1208		this.databaseLocationCombo.setText("");
1209		this.databaseLocationCombo.setEnabled(false);
1210		this.dbLocalBrowseButton.setEnabled(false);
1211		setValid(true);
1212		this.dbLocationLabel.setEnabled(false);
1213	}
1214}
1215
1216}
1217