Refactory
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpdt / internal / ui / preferences / OptionsConfigurationBlock.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.preferences;
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Hashtable;
16 import java.util.Iterator;
17 import java.util.Map;
18 import java.util.StringTokenizer;
19 import java.util.Map.Entry;
20
21 import net.sourceforge.phpdt.core.IJavaProject;
22 import net.sourceforge.phpdt.core.JavaCore;
23 import net.sourceforge.phpdt.internal.ui.wizards.IStatusChangeListener;
24 //import net.sourceforge.phpeclipse.PHPeclipsePlugin;
25 import net.sourceforge.phpeclipse.ui.WebUI;
26
27 import org.eclipse.core.resources.IncrementalProjectBuilder;
28 import org.eclipse.core.resources.ResourcesPlugin;
29 import org.eclipse.core.runtime.CoreException;
30 import org.eclipse.core.runtime.IProgressMonitor;
31 import org.eclipse.core.runtime.IStatus;
32 import org.eclipse.core.runtime.OperationCanceledException;
33 import org.eclipse.core.runtime.Status;
34 import org.eclipse.core.runtime.SubProgressMonitor;
35 import org.eclipse.core.runtime.jobs.Job;
36 import org.eclipse.jface.dialogs.IDialogConstants;
37 import org.eclipse.jface.dialogs.MessageDialog;
38 import org.eclipse.swt.SWT;
39 import org.eclipse.swt.events.ModifyEvent;
40 import org.eclipse.swt.events.ModifyListener;
41 import org.eclipse.swt.events.SelectionEvent;
42 import org.eclipse.swt.events.SelectionListener;
43 import org.eclipse.swt.layout.GridData;
44 import org.eclipse.swt.layout.GridLayout;
45 import org.eclipse.swt.widgets.Button;
46 import org.eclipse.swt.widgets.Combo;
47 import org.eclipse.swt.widgets.Composite;
48 import org.eclipse.swt.widgets.Control;
49 import org.eclipse.swt.widgets.Label;
50 import org.eclipse.swt.widgets.Shell;
51 import org.eclipse.swt.widgets.Text;
52 import org.eclipse.swt.widgets.Widget;
53
54 /**
55  * Abstract options configuration block providing a general implementation for
56  * setting up an options configuration page.
57  * 
58  * @since 2.1
59  */
60 public abstract class OptionsConfigurationBlock {
61
62         protected static class ControlData {
63                 private String fKey;
64
65                 private String[] fValues;
66
67                 public ControlData(String key, String[] values) {
68                         fKey = key;
69                         fValues = values;
70                 }
71
72                 public String getKey() {
73                         return fKey;
74                 }
75
76                 public String getValue(boolean selection) {
77                         int index = selection ? 0 : 1;
78                         return fValues[index];
79                 }
80
81                 public String getValue(int index) {
82                         return fValues[index];
83                 }
84
85                 public int getSelection(String value) {
86                         if (value != null) {
87                                 for (int i = 0; i < fValues.length; i++) {
88                                         if (value.equals(fValues[i])) {
89                                                 return i;
90                                         }
91                                 }
92                         }
93                         return fValues.length - 1; // assume the last option is the least
94                                                                                 // severe
95                 }
96         }
97
98         protected Map fWorkingValues;
99
100         protected ArrayList fCheckBoxes;
101
102         protected ArrayList fComboBoxes;
103
104         protected ArrayList fTextBoxes;
105
106         protected HashMap fLabels;
107
108         private SelectionListener fSelectionListener;
109
110         private ModifyListener fTextModifyListener;
111
112         protected IStatusChangeListener fContext;
113
114         protected IJavaProject fProject; // project or null
115
116         protected String[] fAllKeys;
117
118         private Shell fShell;
119
120         public OptionsConfigurationBlock(IStatusChangeListener context,
121                         IJavaProject project, String[] allKeys) {
122                 fContext = context;
123                 fProject = project;
124                 fAllKeys = allKeys;
125
126                 fWorkingValues = getOptions(true);
127                 testIfOptionsComplete(fWorkingValues, allKeys);
128
129                 fCheckBoxes = new ArrayList();
130                 fComboBoxes = new ArrayList();
131                 fTextBoxes = new ArrayList(2);
132                 fLabels = new HashMap();
133         }
134
135         private void testIfOptionsComplete(Map workingValues, String[] allKeys) {
136                 for (int i = 0; i < allKeys.length; i++) {
137                         if (workingValues.get(allKeys[i]) == null) {
138                                 WebUI
139                                                 .logErrorMessage("preference option missing: " + allKeys[i] + " (" + this.getClass().getName() + ')'); //$NON-NLS-1$//$NON-NLS-2$
140                         }
141                 }
142         }
143
144         protected Map getOptions(boolean inheritJavaCoreOptions) {
145                 if (fProject != null) {
146                         return fProject.getOptions(inheritJavaCoreOptions);
147                 } else {
148                         return JavaCore.getOptions();
149                 }
150         }
151
152         protected Map getDefaultOptions() {
153                 return JavaCore.getDefaultOptions();
154         }
155
156         public final boolean hasProjectSpecificOptions() {
157                 if (fProject != null) {
158                         Map settings = fProject.getOptions(false);
159                         String[] allKeys = fAllKeys;
160                         for (int i = 0; i < allKeys.length; i++) {
161                                 if (settings.get(allKeys[i]) != null) {
162                                         return true;
163                                 }
164                         }
165                 }
166                 return false;
167         }
168
169         protected void setOptions(Map map) {
170                 if (fProject != null) {
171                         Map oldOptions = fProject.getOptions(false);
172                         fProject.setOptions(map);
173                         firePropertyChangeEvents(oldOptions, map);
174                 } else {
175                         JavaCore.setOptions((Hashtable) map);
176                 }
177         }
178
179         /**
180          * Computes the differences between the given old and new options and fires
181          * corresponding property change events on the Java plugin's mockup
182          * preference store.
183          * 
184          * @param oldOptions
185          *            The old options
186          * @param newOptions
187          *            The new options
188          */
189         private void firePropertyChangeEvents(Map oldOptions, Map newOptions) {
190                 oldOptions = new HashMap(oldOptions);
191                 Object source = fProject.getProject();
192                 MockupPreferenceStore store = WebUI.getDefault()
193                                 .getMockupPreferenceStore();
194                 Iterator iter = newOptions.entrySet().iterator();
195                 while (iter.hasNext()) {
196                         Entry entry = (Entry) iter.next();
197
198                         String name = (String) entry.getKey();
199                         Object oldValue = oldOptions.get(name);
200                         Object newValue = entry.getValue();
201
202                         if ((oldValue != null && !oldValue.equals(newValue))
203                                         || (oldValue == null && newValue != null))
204                                 store.firePropertyChangeEvent(source, name, oldValue, newValue);
205                         oldOptions.remove(name);
206                 }
207
208                 iter = oldOptions.entrySet().iterator();
209                 while (iter.hasNext()) {
210                         Entry entry = (Entry) iter.next();
211                         store.firePropertyChangeEvent(source, (String) entry.getKey(),
212                                         entry.getValue(), null);
213                 }
214         }
215
216         protected Shell getShell() {
217                 return fShell;
218         }
219
220         protected void setShell(Shell shell) {
221                 fShell = shell;
222         }
223
224         protected abstract Control createContents(Composite parent);
225
226         protected Button addCheckBox(Composite parent, String label, String key,
227                         String[] values, int indent) {
228                 ControlData data = new ControlData(key, values);
229
230                 GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
231                 gd.horizontalSpan = 3;
232                 gd.horizontalIndent = indent;
233
234                 Button checkBox = new Button(parent, SWT.CHECK);
235                 checkBox.setText(label);
236                 checkBox.setData(data);
237                 checkBox.setLayoutData(gd);
238                 checkBox.addSelectionListener(getSelectionListener());
239
240                 String currValue = (String) fWorkingValues.get(key);
241                 checkBox.setSelection(data.getSelection(currValue) == 0);
242
243                 fCheckBoxes.add(checkBox);
244
245                 return checkBox;
246         }
247
248         protected Combo addComboBox(Composite parent, String label, String key,
249                         String[] values, String[] valueLabels, int indent) {
250                 ControlData data = new ControlData(key, values);
251
252                 GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
253                 gd.horizontalIndent = indent;
254
255                 Label labelControl = new Label(parent, SWT.LEFT | SWT.WRAP);
256                 labelControl.setText(label);
257                 labelControl.setLayoutData(gd);
258
259                 Combo comboBox = new Combo(parent, SWT.READ_ONLY);
260                 comboBox.setItems(valueLabels);
261                 comboBox.setData(data);
262                 comboBox.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
263                 comboBox.addSelectionListener(getSelectionListener());
264
265                 fLabels.put(comboBox, labelControl);
266
267                 Label placeHolder = new Label(parent, SWT.NONE);
268                 placeHolder.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
269
270                 String currValue = (String) fWorkingValues.get(key);
271                 comboBox.select(data.getSelection(currValue));
272
273                 fComboBoxes.add(comboBox);
274                 return comboBox;
275         }
276
277         protected void addInversedComboBox(Composite parent, String label,
278                         String key, String[] values, String[] valueLabels, int indent) {
279                 ControlData data = new ControlData(key, values);
280
281                 GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
282                 gd.horizontalIndent = indent;
283                 gd.horizontalSpan = 3;
284
285                 Composite composite = new Composite(parent, SWT.NONE);
286                 GridLayout layout = new GridLayout();
287                 layout.marginHeight = 0;
288                 layout.marginWidth = 0;
289                 layout.numColumns = 2;
290                 composite.setLayout(layout);
291                 composite.setLayoutData(gd);
292
293                 Combo comboBox = new Combo(composite, SWT.READ_ONLY);
294                 comboBox.setItems(valueLabels);
295                 comboBox.setData(data);
296                 comboBox.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
297                 comboBox.addSelectionListener(getSelectionListener());
298
299                 Label labelControl = new Label(composite, SWT.LEFT | SWT.WRAP);
300                 labelControl.setText(label);
301                 labelControl.setLayoutData(new GridData());
302
303                 fLabels.put(comboBox, labelControl);
304
305                 String currValue = (String) fWorkingValues.get(key);
306                 comboBox.select(data.getSelection(currValue));
307
308                 fComboBoxes.add(comboBox);
309         }
310
311         protected Text addTextField(Composite parent, String label, String key,
312                         int indent, int widthHint) {
313                 Label labelControl = new Label(parent, SWT.NONE);
314                 labelControl.setText(label);
315                 labelControl.setLayoutData(new GridData());
316
317                 Text textBox = new Text(parent, SWT.BORDER | SWT.SINGLE);
318                 textBox.setData(key);
319                 textBox.setLayoutData(new GridData());
320
321                 fLabels.put(textBox, labelControl);
322
323                 String currValue = (String) fWorkingValues.get(key);
324                 if (currValue != null) {
325                         textBox.setText(currValue);
326                 }
327                 textBox.addModifyListener(getTextModifyListener());
328
329                 GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
330                 if (widthHint != 0) {
331                         data.widthHint = widthHint;
332                 }
333                 data.horizontalIndent = indent;
334                 data.horizontalSpan = 2;
335                 textBox.setLayoutData(data);
336
337                 fTextBoxes.add(textBox);
338                 return textBox;
339         }
340
341         protected SelectionListener getSelectionListener() {
342                 if (fSelectionListener == null) {
343                         fSelectionListener = new SelectionListener() {
344                                 public void widgetDefaultSelected(SelectionEvent e) {
345                                 }
346
347                                 public void widgetSelected(SelectionEvent e) {
348                                         controlChanged(e.widget);
349                                 }
350                         };
351                 }
352                 return fSelectionListener;
353         }
354
355         protected ModifyListener getTextModifyListener() {
356                 if (fTextModifyListener == null) {
357                         fTextModifyListener = new ModifyListener() {
358                                 public void modifyText(ModifyEvent e) {
359                                         textChanged((Text) e.widget);
360                                 }
361                         };
362                 }
363                 return fTextModifyListener;
364         }
365
366         protected void controlChanged(Widget widget) {
367                 ControlData data = (ControlData) widget.getData();
368                 String newValue = null;
369                 if (widget instanceof Button) {
370                         newValue = data.getValue(((Button) widget).getSelection());
371                 } else if (widget instanceof Combo) {
372                         newValue = data.getValue(((Combo) widget).getSelectionIndex());
373                 } else {
374                         return;
375                 }
376                 fWorkingValues.put(data.getKey(), newValue);
377
378                 validateSettings(data.getKey(), newValue);
379         }
380
381         protected void textChanged(Text textControl) {
382                 String key = (String) textControl.getData();
383                 String number = textControl.getText();
384                 fWorkingValues.put(key, number);
385                 validateSettings(key, number);
386         }
387
388         protected boolean checkValue(String key, String value) {
389                 return value.equals(fWorkingValues.get(key));
390         }
391
392         /*
393          * (non-javadoc) Update fields and validate. @param changedKey Key that
394          * changed, or null, if all changed.
395          */
396         protected abstract void validateSettings(String changedKey, String newValue);
397
398         protected String[] getTokens(String text, String separator) {
399                 StringTokenizer tok = new StringTokenizer(text, separator); //$NON-NLS-1$
400                 int nTokens = tok.countTokens();
401                 String[] res = new String[nTokens];
402                 for (int i = 0; i < res.length; i++) {
403                         res[i] = tok.nextToken().trim();
404                 }
405                 return res;
406         }
407
408         public boolean performOk(boolean enabled) {
409                 String[] allKeys = fAllKeys;
410                 Map actualOptions = getOptions(false);
411
412                 // preserve other options
413                 boolean hasChanges = false;
414                 for (int i = 0; i < allKeys.length; i++) {
415                         String key = allKeys[i];
416                         String oldVal = (String) actualOptions.get(key);
417                         String val = null;
418                         if (enabled) {
419                                 val = (String) fWorkingValues.get(key);
420                                 if (val != null && !val.equals(oldVal)) {
421                                         hasChanges = true;
422                                         actualOptions.put(key, val);
423                                 }
424                         } else {
425                                 if (oldVal != null) {
426                                         actualOptions.remove(key);
427                                         hasChanges = true;
428                                 }
429                         }
430                 }
431
432                 if (hasChanges) {
433                         boolean doBuild = false;
434                         String[] strings = getFullBuildDialogStrings(fProject == null);
435                         if (strings != null) {
436                                 MessageDialog dialog = new MessageDialog(getShell(),
437                                                 strings[0], null, strings[1], MessageDialog.QUESTION,
438                                                 new String[] { IDialogConstants.YES_LABEL,
439                                                                 IDialogConstants.NO_LABEL,
440                                                                 IDialogConstants.CANCEL_LABEL }, 2);
441                                 int res = dialog.open();
442                                 if (res == 0) {
443                                         doBuild = true;
444                                 } else if (res != 1) {
445                                         return false; // cancel pressed
446                                 }
447                         }
448                         setOptions(actualOptions);
449                         if (doBuild) {
450                                 boolean res = doFullBuild();
451                                 if (!res) {
452                                         return false;
453                                 }
454                         }
455                 }
456                 return true;
457         }
458
459         protected abstract String[] getFullBuildDialogStrings(
460                         boolean workspaceSettings);
461
462         protected boolean doFullBuild() {
463
464                 Job buildJob = new Job(PreferencesMessages
465                                 .getString("OptionsConfigurationBlock.job.title")) { //$NON-NLS-1$
466                         /*
467                          * (non-Javadoc)
468                          * 
469                          * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
470                          */
471                         protected IStatus run(IProgressMonitor monitor) {
472                                 try {
473                                         if (fProject != null) {
474                                                 monitor
475                                                                 .setTaskName(PreferencesMessages
476                                                                                 .getFormattedString(
477                                                                                                 "OptionsConfigurationBlock.buildproject.taskname", fProject.getElementName())); //$NON-NLS-1$
478                                                 fProject.getProject().build(
479                                                                 IncrementalProjectBuilder.FULL_BUILD,
480                                                                 new SubProgressMonitor(monitor, 1));
481                                                 WebUI.getWorkspace().build(
482                                                                 IncrementalProjectBuilder.INCREMENTAL_BUILD,
483                                                                 new SubProgressMonitor(monitor, 1));
484                                         } else {
485                                                 monitor
486                                                                 .setTaskName(PreferencesMessages
487                                                                                 .getString("OptionsConfigurationBlock.buildall.taskname")); //$NON-NLS-1$
488                                                 WebUI.getWorkspace().build(
489                                                                 IncrementalProjectBuilder.FULL_BUILD,
490                                                                 new SubProgressMonitor(monitor, 2));
491                                         }
492                                 } catch (CoreException e) {
493                                         return e.getStatus();
494                                 } catch (OperationCanceledException e) {
495                                         return Status.CANCEL_STATUS;
496                                 } finally {
497                                         monitor.done();
498                                 }
499                                 return Status.OK_STATUS;
500                         }
501
502                         public boolean belongsTo(Object family) {
503                                 return ResourcesPlugin.FAMILY_MANUAL_BUILD == family;
504                         }
505                 };
506
507                 buildJob.setRule(ResourcesPlugin.getWorkspace().getRuleFactory()
508                                 .buildRule());
509                 buildJob.setUser(true);
510                 buildJob.schedule();
511                 return true;
512         }
513
514         public void performDefaults() {
515                 fWorkingValues = getDefaultOptions();
516                 updateControls();
517                 validateSettings(null, null);
518         }
519
520         protected void updateControls() {
521                 // update the UI
522                 for (int i = fCheckBoxes.size() - 1; i >= 0; i--) {
523                         updateCheckBox((Button) fCheckBoxes.get(i));
524                 }
525                 for (int i = fComboBoxes.size() - 1; i >= 0; i--) {
526                         updateCombo((Combo) fComboBoxes.get(i));
527                 }
528                 for (int i = fTextBoxes.size() - 1; i >= 0; i--) {
529                         updateText((Text) fTextBoxes.get(i));
530                 }
531         }
532
533         protected void updateCombo(Combo curr) {
534                 ControlData data = (ControlData) curr.getData();
535
536                 String currValue = (String) fWorkingValues.get(data.getKey());
537                 curr.select(data.getSelection(currValue));
538         }
539
540         protected void updateCheckBox(Button curr) {
541                 ControlData data = (ControlData) curr.getData();
542
543                 String currValue = (String) fWorkingValues.get(data.getKey());
544                 curr.setSelection(data.getSelection(currValue) == 0);
545         }
546
547         protected void updateText(Text curr) {
548                 String key = (String) curr.getData();
549
550                 String currValue = (String) fWorkingValues.get(key);
551                 if (currValue != null) {
552                         curr.setText(currValue);
553                 }
554         }
555
556         protected Button getCheckBox(String key) {
557                 for (int i = fCheckBoxes.size() - 1; i >= 0; i--) {
558                         Button curr = (Button) fCheckBoxes.get(i);
559                         ControlData data = (ControlData) curr.getData();
560                         if (key.equals(data.getKey())) {
561                                 return curr;
562                         }
563                 }
564                 return null;
565         }
566
567         protected Combo getComboBox(String key) {
568                 for (int i = fComboBoxes.size() - 1; i >= 0; i--) {
569                         Combo curr = (Combo) fComboBoxes.get(i);
570                         ControlData data = (ControlData) curr.getData();
571                         if (key.equals(data.getKey())) {
572                                 return curr;
573                         }
574                 }
575                 return null;
576         }
577
578         protected void setComboEnabled(String key, boolean enabled) {
579                 Combo combo = getComboBox(key);
580                 Label label = (Label) fLabels.get(combo);
581                 combo.setEnabled(enabled);
582                 label.setEnabled(enabled);
583         }
584
585 }