Codeformatter preferences should work now
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / preferences / CodeFormatterPreferencePage.java
1 /*
2  * (c) Copyright IBM Corp. 2000, 2001.
3  * All Rights Reserved.
4  */
5 package net.sourceforge.phpdt.internal.ui.preferences;
6
7 import java.io.BufferedReader;
8 import java.io.IOException;
9 import java.io.InputStreamReader;
10 import java.util.ArrayList;
11 import java.util.Hashtable;
12
13 import net.sourceforge.phpdt.core.ICodeFormatter;
14 import net.sourceforge.phpdt.core.ToolFactory;
15 import net.sourceforge.phpdt.internal.ui.PHPUIMessages;
16 import net.sourceforge.phpdt.internal.ui.dialog.StatusInfo;
17 import net.sourceforge.phpdt.internal.ui.dialog.StatusUtil;
18 import net.sourceforge.phpdt.internal.ui.util.TabFolderLayout;
19 import net.sourceforge.phpeclipse.PHPCore;
20 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
21 import net.sourceforge.phpeclipse.phpeditor.PHPSourceViewerConfiguration;
22
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.jface.preference.PreferencePage;
25 import org.eclipse.jface.resource.JFaceResources;
26 import org.eclipse.jface.text.Document;
27 import org.eclipse.jface.text.IDocument;
28 import org.eclipse.jface.text.source.SourceViewer;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.events.ModifyEvent;
31 import org.eclipse.swt.events.ModifyListener;
32 import org.eclipse.swt.events.SelectionEvent;
33 import org.eclipse.swt.events.SelectionListener;
34 import org.eclipse.swt.layout.GridData;
35 import org.eclipse.swt.layout.GridLayout;
36 import org.eclipse.swt.widgets.Button;
37 import org.eclipse.swt.widgets.Composite;
38 import org.eclipse.swt.widgets.Control;
39 import org.eclipse.swt.widgets.Label;
40 import org.eclipse.swt.widgets.TabFolder;
41 import org.eclipse.swt.widgets.TabItem;
42 import org.eclipse.swt.widgets.Text;
43 import org.eclipse.ui.IWorkbench;
44 import org.eclipse.ui.IWorkbenchPreferencePage;
45
46 /*
47  * The page for setting code formatter options
48  */
49 public class CodeFormatterPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
50
51         // Preference store keys, see PHPCore.getOptions
52         private static final String PREF_NEWLINE_OPENING_BRACES= PHPCore.FORMATTER_NEWLINE_OPENING_BRACE; 
53         private static final String PREF_NEWLINE_CONTROL_STATEMENT= PHPCore.FORMATTER_NEWLINE_CONTROL;
54         private static final String PREF_NEWLINE_CLEAR_ALL= PHPCore.FORMATTER_CLEAR_BLANK_LINES;
55         // private static final String PREF_NEWLINE_ELSE_IF= PHPCore.FORMATTER_NEWLINE_ELSE_IF;
56         private static final String PREF_NEWLINE_EMPTY_BLOCK= PHPCore.FORMATTER_NEWLINE_EMPTY_BLOCK;
57         private static final String PREF_LINE_SPLIT= PHPCore.FORMATTER_LINE_SPLIT;
58         private static final String PREF_STYLE_COMPACT_ASSIGNEMENT= PHPCore.FORMATTER_COMPACT_ASSIGNMENT;
59         private static final String PREF_TAB_CHAR= PHPCore.FORMATTER_TAB_CHAR;
60         private static final String PREF_TAB_SIZE= PHPCore.FORMATTER_TAB_SIZE;
61
62         // values
63         private static final String INSERT=  PHPCore.INSERT;
64         private static final String DO_NOT_INSERT= PHPCore.DO_NOT_INSERT;
65         
66         private static final String COMPACT= PHPCore.COMPACT;
67         private static final String NORMAL= PHPCore.NORMAL;
68         
69         private static final String TAB= PHPCore.TAB;
70         private static final String SPACE= PHPCore.SPACE;
71         
72         private static final String CLEAR_ALL= PHPCore.CLEAR_ALL;
73         private static final String PRESERVE_ONE= PHPCore.PRESERVE_ONE;
74         
75
76         private static String[] getAllKeys() {
77                 return new String[] {
78                         PREF_NEWLINE_OPENING_BRACES, PREF_NEWLINE_CONTROL_STATEMENT, PREF_NEWLINE_CLEAR_ALL,
79                 //      PREF_NEWLINE_ELSE_IF, 
80                         PREF_NEWLINE_EMPTY_BLOCK, PREF_LINE_SPLIT,
81                         PREF_STYLE_COMPACT_ASSIGNEMENT, PREF_TAB_CHAR, PREF_TAB_SIZE
82                 };      
83         }
84         
85         /**
86          * Gets the currently configured tab size
87          * @deprecated Inline to avoid reference to preference page
88          */
89         public static int getTabSize() {
90                 String string= (String) PHPCore.getOptions().get(PREF_TAB_SIZE);
91                 return getPositiveIntValue(string, 4);
92         }
93         
94         /**
95          * Gets the current compating assignement configuration
96          * @deprecated Inline to avoid reference to preference page
97          */     
98         public static boolean isCompactingAssignment() {
99                 return COMPACT.equals(PHPCore.getOptions().get(PREF_STYLE_COMPACT_ASSIGNEMENT));
100         }
101         
102         /**
103          * Gets the current compating assignement configuration
104          * @deprecated Inline to avoid reference to preference page
105          */     
106         public static boolean useSpaces() {
107                 return SPACE.equals(PHPCore.getOptions().get(PREF_TAB_CHAR));
108         }       
109         
110         
111         private static int getPositiveIntValue(String string, int dflt) {
112                 try {
113                         int i= Integer.parseInt(string);
114                         if (i >= 0) {
115                                 return i;
116                         }
117                 } catch (NumberFormatException e) {
118                 }
119                 return dflt;
120         }       
121                 
122         private static class ControlData {
123                 private String fKey;
124                 private String[] fValues;
125                 
126                 public ControlData(String key, String[] values) {
127                         fKey= key;
128                         fValues= values;
129                 }
130                 
131                 public String getKey() {
132                         return fKey;
133                 }
134                 
135                 public String getValue(boolean selection) {
136                         int index= selection ? 0 : 1;
137                         return fValues[index];
138                 }
139                 
140                 public String getValue(int index) {
141                         return fValues[index];
142                 }               
143                 
144                 public int getSelection(String value) {
145                         for (int i= 0; i < fValues.length; i++) {
146                                 if (value.equals(fValues[i])) {
147                                         return i;
148                                 }
149                         }
150                         throw new IllegalArgumentException();
151                 }
152         }
153         
154         private Hashtable fWorkingValues;
155
156         private ArrayList fCheckBoxes;
157         private ArrayList fTextBoxes;
158         
159         private SelectionListener fButtonSelectionListener;
160         private ModifyListener fTextModifyListener;
161         
162         private String fPreviewText;
163         private IDocument fPreviewDocument;
164         
165         private Text fTabSizeTextBox;
166  // private SourceViewer fSourceViewer;
167         
168
169         public CodeFormatterPreferencePage() {
170                 setPreferenceStore(PHPeclipsePlugin.getDefault().getPreferenceStore());         
171                 setDescription(PHPUIMessages.getString("CodeFormatterPreferencePage.description")); //$NON-NLS-1$
172         
173                 fWorkingValues= PHPCore.getOptions();
174                 fCheckBoxes= new ArrayList();
175                 fTextBoxes= new ArrayList();
176                 
177                 fButtonSelectionListener= new SelectionListener() {
178                         public void widgetDefaultSelected(SelectionEvent e) {}
179
180                         public void widgetSelected(SelectionEvent e) {
181                                 if (!e.widget.isDisposed()) {
182                                         controlChanged((Button) e.widget);
183                                 }
184                         }
185                 };
186                 
187                 fTextModifyListener= new ModifyListener() {
188                         public void modifyText(ModifyEvent e) {
189                                 if (!e.widget.isDisposed()) {
190                                         textChanged((Text) e.widget);
191                                 }
192                         }
193                 };
194                 
195                 fPreviewDocument= new Document();
196                 fPreviewText= loadPreviewFile("CodeFormatterPreviewCode.txt");  //$NON-NLS-1$   
197         }
198
199         /*
200          * @see IWorkbenchPreferencePage#init()
201          */     
202         public void init(IWorkbench workbench) {
203         }
204
205         /*
206          * @see PreferencePage#createControl(Composite)
207          */
208         public void createControl(Composite parent) {
209                 super.createControl(parent);
210 //              WorkbenchHelp.setHelp(getControl(), IJavaHelpContextIds.CODEFORMATTER_PREFERENCE_PAGE);
211         }       
212
213         /*
214          * @see PreferencePage#createContents(Composite)
215          */
216         protected Control createContents(Composite parent) {
217                 
218                 GridLayout layout= new GridLayout();
219                 layout.marginHeight= 0;
220                 layout.marginWidth= 0;
221                 
222                 Composite composite= new Composite(parent, SWT.NONE);
223                 composite.setLayout(layout);
224                                 
225                         
226                 TabFolder folder= new TabFolder(composite, SWT.NONE);
227                 folder.setLayout(new TabFolderLayout());        
228                 folder.setLayoutData(new GridData(GridData.FILL_BOTH));
229                 
230                 String[] insertNotInsert= new String[] { INSERT, DO_NOT_INSERT };
231                 
232                 layout= new GridLayout();
233                 layout.numColumns= 2;
234                 
235                 Composite newlineComposite= new Composite(folder, SWT.NULL);
236                 newlineComposite.setLayout(layout);
237
238                 String label= PHPUIMessages.getString("CodeFormatterPreferencePage.newline_opening_braces.label"); //$NON-NLS-1$
239                 addCheckBox(newlineComposite, label, PREF_NEWLINE_OPENING_BRACES, insertNotInsert);     
240                 
241                 label= PHPUIMessages.getString("CodeFormatterPreferencePage.newline_control_statement.label"); //$NON-NLS-1$
242                 addCheckBox(newlineComposite, label, PREF_NEWLINE_CONTROL_STATEMENT, insertNotInsert);  
243
244                 label= PHPUIMessages.getString("CodeFormatterPreferencePage.newline_clear_lines"); //$NON-NLS-1$
245                 addCheckBox(newlineComposite, label, PREF_NEWLINE_CLEAR_ALL, new String[] { CLEAR_ALL, PRESERVE_ONE } );        
246
247 //              label= PHPUIMessages.getString("CodeFormatterPreferencePage.newline_else_if.label"); //$NON-NLS-1$
248 //              addCheckBox(newlineComposite, label, PREF_NEWLINE_ELSE_IF, insertNotInsert);    
249
250                 label= PHPUIMessages.getString("CodeFormatterPreferencePage.newline_empty_block.label"); //$NON-NLS-1$
251                 addCheckBox(newlineComposite, label, PREF_NEWLINE_EMPTY_BLOCK, insertNotInsert);        
252                 
253                 layout= new GridLayout();
254                 layout.numColumns= 2;   
255                 
256                 Composite lineSplittingComposite= new Composite(folder, SWT.NULL);
257                 lineSplittingComposite.setLayout(layout);
258
259                 label= PHPUIMessages.getString("CodeFormatterPreferencePage.split_line.label"); //$NON-NLS-1$
260                 addTextField(lineSplittingComposite, label, PREF_LINE_SPLIT);
261
262                 layout= new GridLayout();
263                 layout.numColumns= 2;   
264                 
265                 Composite styleComposite= new Composite(folder, SWT.NULL);
266                 styleComposite.setLayout(layout);
267                 
268                 label= PHPUIMessages.getString("CodeFormatterPreferencePage.style_compact_assignement.label"); //$NON-NLS-1$
269                 addCheckBox(styleComposite, label, PREF_STYLE_COMPACT_ASSIGNEMENT, new String[] { COMPACT, NORMAL } );          
270
271                 label= PHPUIMessages.getString("CodeFormatterPreferencePage.tab_char.label"); //$NON-NLS-1$
272                 addCheckBox(styleComposite, label, PREF_TAB_CHAR, new String[] { TAB, SPACE } );                
273
274                 label= PHPUIMessages.getString("CodeFormatterPreferencePage.tab_size.label"); //$NON-NLS-1$
275                 fTabSizeTextBox= addTextField(styleComposite, label, PREF_TAB_SIZE);            
276
277                 TabItem item= new TabItem(folder, SWT.NONE);
278                 item.setText(PHPUIMessages.getString("CodeFormatterPreferencePage.tab.newline.tabtitle")); //$NON-NLS-1$
279                 item.setControl(newlineComposite);
280
281                 item= new TabItem(folder, SWT.NONE);
282                 item.setText(PHPUIMessages.getString("CodeFormatterPreferencePage.tab.linesplit.tabtitle")); //$NON-NLS-1$
283                 item.setControl(lineSplittingComposite);
284                 
285                 item= new TabItem(folder, SWT.NONE);
286                 item.setText(PHPUIMessages.getString("CodeFormatterPreferencePage.tab.style.tabtitle")); //$NON-NLS-1$
287                 item.setControl(styleComposite);                
288                 
289 //              fSourceViewer= createPreview(parent);
290                         
291                 updatePreview();
292                                         
293                 return composite;
294         }
295         
296 //      private SourceViewer createPreview(Composite parent) {
297 //              SourceViewer previewViewer= new SourceViewer(parent, null, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
298 //              JavaTextTools tools= JavaPlugin.getDefault().getJavaTextTools();
299 //              previewViewer.configure(new PHPSourceViewerConfiguration(tools, null));
300 //              previewViewer.getTextWidget().setFont(JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT));
301 //              previewViewer.getTextWidget().setTabs(getPositiveIntValue((String) fWorkingValues.get(PREF_TAB_SIZE), 0));
302 //              previewViewer.setEditable(false);
303 //              previewViewer.setDocument(fPreviewDocument);
304 //              Control control= previewViewer.getControl();
305 //              GridData gdata= new GridData(GridData.FILL_BOTH);
306 //              gdata.widthHint= convertWidthInCharsToPixels(30);
307 //              gdata.heightHint= convertHeightInCharsToPixels(5);
308 //              control.setLayoutData(gdata);
309 //              return previewViewer;
310 //      }
311
312         
313         private Button addCheckBox(Composite parent, String label, String key, String[] values) {
314                 ControlData data= new ControlData(key, values);
315                 
316                 GridData gd= new GridData(GridData.FILL_HORIZONTAL);
317                 gd.horizontalSpan= 2;
318                 
319                 Button checkBox= new Button(parent, SWT.CHECK);
320                 checkBox.setText(label);
321                 checkBox.setData(data);
322                 checkBox.setLayoutData(gd);
323                 
324                 String currValue= (String)fWorkingValues.get(key);      
325                 checkBox.setSelection(data.getSelection(currValue) == 0);
326                 checkBox.addSelectionListener(fButtonSelectionListener);
327                 
328                 fCheckBoxes.add(checkBox);
329                 return checkBox;
330         }
331         
332         private Text addTextField(Composite parent, String label, String key) { 
333                 Label labelControl= new Label(parent, SWT.NONE);
334                 labelControl.setText(label);
335                 labelControl.setLayoutData(new GridData());
336                                 
337                 Text textBox= new Text(parent, SWT.BORDER | SWT.SINGLE);
338                 textBox.setData(key);
339                 textBox.setLayoutData(new GridData());
340                 
341                 String currValue= (String)fWorkingValues.get(key);      
342                 textBox.setText(String.valueOf(getPositiveIntValue(currValue, 1)));
343                 textBox.setTextLimit(3);
344                 textBox.addModifyListener(fTextModifyListener);
345
346                 GridData gd= new GridData();
347                 gd.widthHint= convertWidthInCharsToPixels(5);
348                 textBox.setLayoutData(gd);
349
350                 fTextBoxes.add(textBox);
351                 return textBox;
352         }       
353         
354         private void controlChanged(Button button) {
355                 ControlData data= (ControlData) button.getData();
356                 boolean selection= button.getSelection();
357                 String newValue= data.getValue(selection);      
358                 fWorkingValues.put(data.getKey(), newValue);
359                 updatePreview();
360                 
361                 if (PREF_TAB_CHAR.equals(data.getKey())) {
362                         updateStatus(new StatusInfo());
363                         if (selection) {
364                                 fTabSizeTextBox.setText((String)fWorkingValues.get(PREF_TAB_SIZE));
365                         }
366                 }
367         }
368         
369         private void textChanged(Text textControl) {
370                 String key= (String) textControl.getData();
371                 String number= textControl.getText();
372                 IStatus status= validatePositiveNumber(number);
373                 if (!status.matches(IStatus.ERROR)) {
374                         fWorkingValues.put(key, number);
375                 }
376 //              if (PREF_TAB_SIZE.equals(key)) {
377 //                      fSourceViewer.getTextWidget().setTabs(getPositiveIntValue(number, 0));
378 //              }                       
379                 updateStatus(status);
380                 updatePreview();
381         }
382                 
383         
384         /*
385          * @see IPreferencePage#performOk()
386          */
387         public boolean performOk() {
388                 String[] allKeys= getAllKeys();
389                 // preserve other options
390                 // store in JCore
391                 Hashtable actualOptions= PHPCore.getOptions();
392                 for (int i= 0; i < allKeys.length; i++) {
393                         String key= allKeys[i];
394                         String val=  (String) fWorkingValues.get(key);
395                         actualOptions.put(key, val);
396                 }
397                 PHPCore.setOptions(actualOptions);
398                 PHPeclipsePlugin.getDefault().savePluginPreferences();
399                 return super.performOk();
400         }       
401         
402         /*
403          * @see PreferencePage#performDefaults()
404          */
405         protected void performDefaults() {
406                 fWorkingValues= PHPCore.getDefaultOptions();
407                 updateControls();
408                 super.performDefaults();
409         }
410
411         private String loadPreviewFile(String filename) {
412                 String separator= System.getProperty("line.separator"); //$NON-NLS-1$
413                 StringBuffer btxt= new StringBuffer(512);
414                 BufferedReader rin= null;
415                 try {
416                         rin= new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(filename)));
417                         String line;
418                         while ((line= rin.readLine()) != null) {
419                                 btxt.append(line);
420                                 btxt.append(separator);
421                         }
422                 } catch (IOException io) {
423                         PHPeclipsePlugin.log(io);
424                 } finally {
425                         if (rin != null) {
426                                 try { rin.close(); } catch (IOException e) {}
427                         }
428                 }
429                 return btxt.toString();
430         }
431
432
433         private void updatePreview() {
434                 ICodeFormatter formatter= ToolFactory.createDefaultCodeFormatter(fWorkingValues);
435                 fPreviewDocument.set(formatter.format(fPreviewText, 0, null, "\n")); //$NON-NLS-1$
436         }       
437         
438         private void updateControls() {
439                 // update the UI
440                 for (int i= fCheckBoxes.size() - 1; i >= 0; i--) {
441                         Button curr= (Button) fCheckBoxes.get(i);
442                         ControlData data= (ControlData) curr.getData();
443                                         
444                         String currValue= (String) fWorkingValues.get(data.getKey());   
445                         curr.setSelection(data.getSelection(currValue) == 0);                   
446                 }
447                 for (int i= fTextBoxes.size() - 1; i >= 0; i--) {
448                         Text curr= (Text) fTextBoxes.get(i);
449                         String key= (String) curr.getData();            
450                         String currValue= (String) fWorkingValues.get(key);
451                         curr.setText(currValue);
452                 }
453         }
454         
455         private IStatus validatePositiveNumber(String number) {
456                 StatusInfo status= new StatusInfo();
457                 if (number.length() == 0) {
458                         status.setError(PHPUIMessages.getString("CodeFormatterPreferencePage.empty_input")); //$NON-NLS-1$
459                 } else {
460                         try {
461                                 int value= Integer.parseInt(number);
462                                 if (value < 0) {
463                                         status.setError(PHPUIMessages.getFormattedString("CodeFormatterPreferencePage.invalid_input", number)); //$NON-NLS-1$
464                                 }
465                         } catch (NumberFormatException e) {
466                                 status.setError(PHPUIMessages.getFormattedString("CodeFormatterPreferencePage.invalid_input", number)); //$NON-NLS-1$
467                         }
468                 }
469                 return status;
470         }
471                         
472         
473         private void updateStatus(IStatus status) {
474                 if (!status.matches(IStatus.ERROR)) {
475                         // look if there are more severe errors
476                         for (int i= 0; i < fTextBoxes.size(); i++) {
477                                 Text curr= (Text) fTextBoxes.get(i);
478                                 if (!(curr == fTabSizeTextBox && usesTabs())) {
479                                         IStatus currStatus= validatePositiveNumber(curr.getText());
480                                         status= StatusUtil.getMoreSevere(currStatus, status);
481                                 }
482                         }
483                 }       
484                 setValid(!status.matches(IStatus.ERROR));
485                 StatusUtil.applyToStatusLine(this, status);
486         }
487         
488         private boolean usesTabs() {
489                 return TAB.equals(fWorkingValues.get(PREF_TAB_CHAR));
490         }
491                 
492
493 }
494
495