1 /*******************************************************************************
2 * Copyright (c) 2010, SAP AG.
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
9 * Mathias Kinzler (SAP AG) - initial implementation
10 *******************************************************************************/
11 package org
.eclipse
.egit
.ui
.internal
.preferences
;
14 import java
.io
.IOException
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Arrays
;
17 import java
.util
.Collections
;
18 import java
.util
.Comparator
;
19 import java
.util
.List
;
21 import java
.util
.StringTokenizer
;
23 import org
.eclipse
.core
.filesystem
.EFS
;
24 import org
.eclipse
.core
.filesystem
.IFileStore
;
25 import org
.eclipse
.core
.runtime
.Path
;
26 import org
.eclipse
.egit
.ui
.Activator
;
27 import org
.eclipse
.egit
.ui
.internal
.UIText
;
28 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
29 import org
.eclipse
.jface
.layout
.GridDataFactory
;
30 import org
.eclipse
.jface
.layout
.GridLayoutFactory
;
31 import org
.eclipse
.jface
.resource
.JFaceResources
;
32 import org
.eclipse
.jface
.viewers
.BaseLabelProvider
;
33 import org
.eclipse
.jface
.viewers
.CellEditor
;
34 import org
.eclipse
.jface
.viewers
.EditingSupport
;
35 import org
.eclipse
.jface
.viewers
.ICellEditorListener
;
36 import org
.eclipse
.jface
.viewers
.ICellEditorValidator
;
37 import org
.eclipse
.jface
.viewers
.IFontProvider
;
38 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
39 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
40 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
41 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
42 import org
.eclipse
.jface
.viewers
.TextCellEditor
;
43 import org
.eclipse
.jface
.viewers
.TreeViewer
;
44 import org
.eclipse
.jface
.viewers
.TreeViewerColumn
;
45 import org
.eclipse
.jface
.window
.IShellProvider
;
46 import org
.eclipse
.jface
.window
.SameShellProvider
;
47 import org
.eclipse
.jface
.window
.Window
;
48 import org
.eclipse
.jgit
.errors
.ConfigInvalidException
;
49 import org
.eclipse
.jgit
.lib
.Config
;
50 import org
.eclipse
.jgit
.lib
.StoredConfig
;
51 import org
.eclipse
.jgit
.storage
.file
.FileBasedConfig
;
52 import org
.eclipse
.osgi
.util
.NLS
;
53 import org
.eclipse
.swt
.SWT
;
54 import org
.eclipse
.swt
.events
.SelectionAdapter
;
55 import org
.eclipse
.swt
.events
.SelectionEvent
;
56 import org
.eclipse
.swt
.graphics
.Font
;
57 import org
.eclipse
.swt
.graphics
.FontData
;
58 import org
.eclipse
.swt
.graphics
.Image
;
59 import org
.eclipse
.swt
.layout
.GridLayout
;
60 import org
.eclipse
.swt
.widgets
.Button
;
61 import org
.eclipse
.swt
.widgets
.Composite
;
62 import org
.eclipse
.swt
.widgets
.Control
;
63 import org
.eclipse
.swt
.widgets
.Display
;
64 import org
.eclipse
.swt
.widgets
.Label
;
65 import org
.eclipse
.swt
.widgets
.Shell
;
66 import org
.eclipse
.swt
.widgets
.Text
;
67 import org
.eclipse
.swt
.widgets
.Tree
;
68 import org
.eclipse
.swt
.widgets
.TreeColumn
;
69 import org
.eclipse
.ui
.PartInitException
;
70 import org
.eclipse
.ui
.PlatformUI
;
71 import org
.eclipse
.ui
.editors
.text
.EditorsUI
;
72 import org
.eclipse
.ui
.ide
.FileStoreEditorInput
;
73 import org
.eclipse
.ui
.ide
.IDE
;
74 import org
.eclipse
.ui
.model
.WorkbenchAdapter
;
75 import org
.eclipse
.ui
.model
.WorkbenchContentProvider
;
78 * A reusable UI component to display and edit a Git configuration.
80 * Concrete subclasses that are interested in displaying error messages should
81 * override {@link #setErrorMessage(String)}
83 * TODO: do the changes in memory and offer methods to obtain dirty state, to
84 * save, and something like setDirty(boolean) to be implemented by subclasses so
85 * that proper save/revert can be implemented; we could also offer this for
86 * non-stored configurations
88 public class ConfigurationEditorComponent
{
90 private final static String DOT
= "."; //$NON-NLS-1$
92 private StoredConfig editableConfig
;
94 private final IShellProvider shellProvider
;
96 private final Composite parent
;
98 private final boolean useDialogFont
;
100 private Composite contents
;
102 private Button newValue
;
104 private Button remove
;
106 private TreeViewer tv
;
108 private Text location
;
110 private boolean editable
;
116 * to be used instead of the user configuration
117 * @param useDialogFont
118 * if <code>true</code>, the current dialog font is used
120 public ConfigurationEditorComponent(Composite parent
, StoredConfig config
,
121 boolean useDialogFont
) {
122 editableConfig
= config
;
123 this.shellProvider
= new SameShellProvider(parent
);
124 this.parent
= parent
;
125 this.useDialogFont
= useDialogFont
;
128 void setConfig(FileBasedConfig config
) throws IOException
{
129 editableConfig
= config
;
131 editableConfig
.clear();
132 editableConfig
.load();
133 } catch (ConfigInvalidException e
) {
134 throw new IOException(e
.getMessage());
136 initControlsFromConfig();
140 * Saves and (in case of success) reloads the current configuration
142 * @throws IOException
144 public void save() throws IOException
{
145 editableConfig
.save();
147 initControlsFromConfig();
151 * Restores and (in case of success) reloads the current configuration
153 * @throws IOException
155 public void restore() throws IOException
{
157 editableConfig
.clear();
158 editableConfig
.load();
159 } catch (ConfigInvalidException e
) {
160 throw new IOException(e
.getMessage());
162 initControlsFromConfig();
166 * @return the control being created
168 public Control
createContents() {
169 final Composite main
= new Composite(parent
, SWT
.NONE
);
170 main
.setLayout(new GridLayout(2, false));
171 GridDataFactory
.fillDefaults().grab(true, true).applyTo(main
);
173 if (editableConfig
instanceof FileBasedConfig
) {
174 Composite locationPanel
= new Composite(main
, SWT
.NONE
);
175 GridLayout locationLayout
= new GridLayout(3, false);
176 locationLayout
.marginWidth
= 0;
177 locationPanel
.setLayout(locationLayout
);
178 GridDataFactory
.fillDefaults().grab(true, false).span(2, 1)
179 .applyTo(locationPanel
);
180 Label locationLabel
= new Label(locationPanel
, SWT
.NONE
);
182 .setText(UIText
.ConfigurationEditorComponent_ConfigLocationLabel
);
183 // GridDataFactory.fillDefaults().applyTo(locationLabel);
184 int locationStyle
= SWT
.BORDER
|SWT
.READ_ONLY
;
185 location
= new Text(locationPanel
, locationStyle
);
186 GridDataFactory
.fillDefaults().align(SWT
.FILL
, SWT
.CENTER
)
187 .grab(true, false).applyTo(location
);
188 Button openEditor
= new Button(locationPanel
, SWT
.PUSH
);
190 .setText(UIText
.ConfigurationEditorComponent_OpenEditorButton
);
192 .setToolTipText(UIText
.ConfigurationEditorComponent_OpenEditorTooltip
);
193 openEditor
.addSelectionListener(new SelectionAdapter() {
195 public void widgetSelected(SelectionEvent e
) {
196 IFileStore store
= EFS
.getLocalFileSystem().getStore(
197 new Path(((FileBasedConfig
) editableConfig
)
198 .getFile().getAbsolutePath()));
200 IDE
.openEditor(PlatformUI
.getWorkbench()
201 .getActiveWorkbenchWindow().getActivePage(),
202 new FileStoreEditorInput(store
),
203 EditorsUI
.DEFAULT_TEXT_EDITOR_ID
);
204 } catch (PartInitException ex
) {
205 Activator
.handleError(ex
.getMessage(), ex
, true);
210 .setEnabled(((FileBasedConfig
) editableConfig
).getFile() != null);
212 tv
= new TreeViewer(main
, SWT
.SINGLE
| SWT
.FULL_SELECTION
| SWT
.BORDER
);
213 Tree tree
= tv
.getTree();
214 GridDataFactory
.fillDefaults().hint(100, 60).grab(true, true)
216 TreeColumn key
= new TreeColumn(tree
, SWT
.NONE
);
217 key
.setText(UIText
.ConfigurationEditorComponent_KeyColumnHeader
);
220 final TextCellEditor editor
= new TextCellEditor(tree
);
221 editor
.setValidator(new ICellEditorValidator() {
224 public String
isValid(Object value
) {
225 String editedValue
= value
.toString();
226 return editedValue
.length() > 0 ?
null
227 : UIText
.ConfigurationEditorComponent_EmptyStringNotAllowed
;
230 editor
.addListener(new ICellEditorListener() {
233 public void editorValueChanged(boolean oldValidState
,
234 boolean newValidState
) {
235 setErrorMessage(editor
.getErrorMessage());
239 public void cancelEditor() {
240 setErrorMessage(null);
244 public void applyEditorValue() {
245 setErrorMessage(null);
249 TreeColumn value
= new TreeColumn(tree
, SWT
.NONE
);
250 value
.setText(UIText
.ConfigurationEditorComponent_ValueColumnHeader
);
252 new TreeViewerColumn(tv
, value
)
253 .setEditingSupport(new EditingSupport(tv
) {
256 protected void setValue(Object element
, Object newValue
) {
257 Entry entry
= (Entry
) element
;
258 if (!entry
.value
.equals(newValue
)) {
259 entry
.changeValue(newValue
.toString());
265 protected Object
getValue(Object element
) {
266 return ((Entry
) element
).value
;
270 protected CellEditor
getCellEditor(Object element
) {
275 protected boolean canEdit(Object element
) {
276 return editable
&& element
instanceof Entry
;
280 tv
.setContentProvider(new WorkbenchContentProvider());
283 defaultFont
= JFaceResources
.getDialogFont();
285 defaultFont
= JFaceResources
.getDefaultFont();
286 tv
.setLabelProvider(new ConfigEditorLabelProvider(defaultFont
));
288 tree
.setHeaderVisible(true);
289 tree
.setLinesVisible(true);
291 Composite buttonPanel
= new Composite(main
, SWT
.NONE
);
292 GridLayoutFactory
.fillDefaults().applyTo(buttonPanel
);
293 GridDataFactory
.fillDefaults().grab(false, false).applyTo(buttonPanel
);
294 newValue
= new Button(buttonPanel
, SWT
.PUSH
);
295 GridDataFactory
.fillDefaults().applyTo(newValue
);
296 newValue
.setText(UIText
.ConfigurationEditorComponent_AddButton
);
297 newValue
.addSelectionListener(new SelectionAdapter() {
299 public void widgetSelected(SelectionEvent e
) {
302 IStructuredSelection sel
= (IStructuredSelection
) tv
304 Object first
= sel
.getFirstElement();
305 if (first
instanceof Section
)
306 suggestedKey
= ((Section
) first
).name
+ DOT
;
307 else if (first
instanceof SubSection
) {
308 SubSection sub
= (SubSection
) first
;
309 suggestedKey
= sub
.parent
.name
+ DOT
+ sub
.name
+ DOT
;
310 } else if (first
instanceof Entry
) {
311 Entry entry
= (Entry
) first
;
312 if (entry
.sectionparent
!= null)
313 suggestedKey
= entry
.sectionparent
.name
+ DOT
;
315 suggestedKey
= entry
.subsectionparent
.parent
.name
+ DOT
316 + entry
.subsectionparent
.name
+ DOT
;
320 AddConfigEntryDialog dlg
= new AddConfigEntryDialog(getShell(),
322 if (dlg
.open() == Window
.OK
) {
323 String result
= dlg
.getKey();
324 if (result
== null) {
325 // bug in swt bot, see
326 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=472110
329 StringTokenizer st
= new StringTokenizer(result
, DOT
);
330 if (st
.countTokens() == 2) {
331 String sectionName
= st
.nextToken();
332 String entryName
= st
.nextToken();
333 Entry entry
= ((GitConfig
) tv
.getInput()).getEntry(
334 sectionName
, null, entryName
);
336 editableConfig
.setString(sectionName
, null,
337 entryName
, dlg
.getValue());
339 entry
.addValue(dlg
.getValue());
341 } else if (st
.countTokens() > 2) {
342 int n
= st
.countTokens();
343 String sectionName
= st
.nextToken();
344 StringBuilder b
= new StringBuilder(st
.nextToken());
345 for (int i
= 0; i
< n
- 3; i
++) {
347 b
.append(st
.nextToken());
349 String subSectionName
= b
.toString();
350 String entryName
= st
.nextToken();
351 Entry entry
= ((GitConfig
) tv
.getInput()).getEntry(
352 sectionName
, subSectionName
, entryName
);
354 editableConfig
.setString(sectionName
,
355 subSectionName
, entryName
, dlg
.getValue());
357 entry
.addValue(dlg
.getValue());
362 UIText
.ConfigurationEditorComponent_WrongNumberOfTokensMessage
,
368 remove
= new Button(buttonPanel
, SWT
.PUSH
);
369 GridDataFactory
.fillDefaults().applyTo(remove
);
370 remove
.setText(UIText
.ConfigurationEditorComponent_RemoveButton
);
371 remove
.setToolTipText(UIText
.ConfigurationEditorComponent_RemoveTooltip
);
372 remove
.addSelectionListener(new SelectionAdapter() {
374 public void widgetSelected(SelectionEvent e
) {
375 IStructuredSelection sel
= (IStructuredSelection
) tv
377 Object first
= sel
.getFirstElement();
378 if (first
instanceof Section
) {
379 Section section
= (Section
) first
;
383 UIText
.ConfigurationEditorComponent_RemoveSectionTitle
,
385 UIText
.ConfigurationEditorComponent_RemoveSectionMessage
,
387 editableConfig
.unsetSection(section
.name
, null);
390 } else if (first
instanceof SubSection
) {
391 SubSection section
= (SubSection
) first
;
395 UIText
.ConfigurationEditorComponent_RemoveSubsectionTitle
,
397 UIText
.ConfigurationEditorComponent_RemoveSubsectionMessage
,
398 section
.parent
.name
+ DOT
400 editableConfig
.unsetSection(section
.parent
.name
,
404 } else if (first
instanceof Entry
) {
405 ((Entry
) first
).removeValue();
409 super.widgetSelected(e
);
413 tv
.addSelectionChangedListener(new ISelectionChangedListener() {
415 public void selectionChanged(SelectionChangedEvent event
) {
420 initControlsFromConfig();
426 * @return the composite containing all the controls
428 public Composite
getContents() {
432 private boolean isWriteable(final File f
) {
441 // no file, can we create one
442 for (File d
= f
.getParentFile(); d
!= null; d
= d
.getParentFile())
454 private void initControlsFromConfig() {
456 editableConfig
.load();
457 tv
.setInput(new GitConfig(editableConfig
));
459 if (editableConfig
instanceof FileBasedConfig
) {
460 FileBasedConfig fileConfig
= (FileBasedConfig
) editableConfig
;
461 File configFile
= fileConfig
.getFile();
462 if (configFile
!= null)
463 if (isWriteable(configFile
))
464 location
.setText(configFile
.getPath());
467 .bind(UIText
.ConfigurationEditorComponent_ReadOnlyLocationFormat
,
468 configFile
.getPath()));
472 location
.setText(UIText
.ConfigurationEditorComponent_NoConfigLocationKnown
);
476 } catch (IOException e
) {
477 Activator
.handleError(e
.getMessage(), e
, true);
478 } catch (ConfigInvalidException e
) {
479 Activator
.handleError(e
.getMessage(), e
, true);
487 * the error message to display
489 protected void setErrorMessage(String message
) {
490 // the default implementation does nothing
497 protected void setDirty(boolean dirty
) {
498 // the default implementation does nothing
501 private void updateEnablement() {
502 remove
.setEnabled(editable
&& !tv
.getSelection().isEmpty());
503 newValue
.setEnabled(editable
);
506 private void markDirty() {
508 ((GitConfig
) tv
.getInput()).refresh();
512 private final static class GitConfig
extends WorkbenchAdapter
{
514 private final Config config
;
516 private Section
[] children
;
518 GitConfig(Config config
) {
519 this.config
= config
;
522 GitConfig
refresh() {
528 public Object
[] getChildren(Object o
) {
529 if (children
== null)
530 if (config
!= null) {
531 List
<Section
> sections
= new ArrayList
<>();
532 Set
<String
> sectionNames
= config
.getSections();
533 for (String sectionName
: sectionNames
)
534 sections
.add(new Section(this, sectionName
));
535 Collections
.sort(sections
, new Comparator
<Section
>() {
538 public int compare(Section o1
, Section o2
) {
539 return o1
.name
.compareTo(o2
.name
);
542 children
= sections
.toArray(new Section
[sections
.size()]);
544 children
= new Section
[0];
548 public Entry
getEntry(String sectionName
, String subsectionName
,
550 for (Object child
: getChildren(this)) {
551 Section section
= (Section
) child
;
552 if (sectionName
.equals(section
.name
))
553 return section
.getEntry(subsectionName
, entryName
);
559 private final static class Section
extends WorkbenchAdapter
{
560 private final String name
;
562 private final GitConfig parent
;
564 private Object
[] children
;
566 Section(GitConfig parent
, String name
) {
567 this.parent
= parent
;
572 public int hashCode() {
573 final int prime
= 31;
575 result
= prime
* result
+ name
.hashCode();
580 public boolean equals(Object obj
) {
585 if (getClass() != obj
.getClass())
587 Section other
= (Section
) obj
;
588 if (!name
.equals(other
.name
))
594 public Object
getParent(Object object
) {
599 public Object
[] getChildren(Object o
) {
600 if (children
== null) {
601 List
<Object
> allChildren
= new ArrayList
<>();
602 Set
<String
> subSectionNames
= parent
.config
603 .getSubsections(name
);
604 for (String subSectionName
: subSectionNames
)
605 allChildren
.add(new SubSection(parent
.config
, this,
608 Set
<String
> entryNames
= parent
.config
.getNames(name
);
609 for (String entryName
: entryNames
) {
610 String
[] values
= parent
.config
.getStringList(name
, null,
612 if (values
.length
== 1)
613 allChildren
.add(new Entry(this, entryName
, values
[0],
617 for (String value
: values
)
618 allChildren
.add(new Entry(this, entryName
, value
,
622 children
= allChildren
.toArray();
628 public String
getLabel(Object o
) {
632 public Entry
getEntry(String subsectionName
, String entryName
) {
633 if (subsectionName
!= null) {
634 for (Object child
: getChildren(this))
635 if (child
instanceof SubSection
636 && ((SubSection
) child
).name
.equals(subsectionName
))
637 return ((SubSection
) child
).getEntry(entryName
);
639 for (Object child
: getChildren(this))
640 if (child
instanceof Entry
641 && ((Entry
) child
).name
.equals(entryName
))
642 return (Entry
) child
;
647 private final static class SubSection
extends WorkbenchAdapter
{
649 private final Config config
;
651 private final Section parent
;
653 private final String name
;
655 private Entry
[] children
;
657 SubSection(Config config
, Section parent
, String name
) {
658 this.config
= config
;
659 this.parent
= parent
;
664 public int hashCode() {
665 final int prime
= 31;
667 result
= prime
* result
+ name
.hashCode();
668 result
= prime
* result
+ parent
.hashCode();
673 public boolean equals(Object obj
) {
678 if (getClass() != obj
.getClass())
680 SubSection other
= (SubSection
) obj
;
681 if (!name
.equals(other
.name
))
683 if (!parent
.equals(other
.parent
))
689 public Object
[] getChildren(Object o
) {
690 if (children
== null) {
691 List
<Entry
> entries
= new ArrayList
<>();
692 Set
<String
> entryNames
= config
.getNames(parent
.name
, name
);
693 for (String entryName
: entryNames
) {
694 String
[] values
= config
.getStringList(parent
.name
, name
,
696 if (values
.length
== 1)
697 entries
.add(new Entry(this, entryName
, values
[0], -1));
700 for (String value
: values
)
701 entries
.add(new Entry(this, entryName
, value
,
705 children
= entries
.toArray(new Entry
[entries
.size()]);
711 public String
getLabel(Object o
) {
716 public Object
getParent(Object object
) {
720 public Entry
getEntry(String entryName
) {
721 for (Object child
: getChildren(this))
722 if (entryName
.equals(((Entry
) child
).name
))
723 return (Entry
) child
;
728 private final static class Entry
extends WorkbenchAdapter
{
730 private final Section sectionparent
;
732 private final SubSection subsectionparent
;
734 private final String name
;
736 private final String value
;
738 private final int index
;
740 Entry(Section parent
, String name
, String value
, int index
) {
741 this.sectionparent
= parent
;
742 this.subsectionparent
= null;
748 public void addValue(String newValue
) {
749 if (newValue
.length() == 0)
750 throw new IllegalArgumentException(
751 UIText
.ConfigurationEditorComponent_EmptyStringNotAllowed
);
752 Config config
= getConfig();
754 List
<String
> entries
;
755 if (sectionparent
!= null) {
756 // Arrays.asList returns a fixed-size list, so we need to copy
757 // over to a mutable list
758 entries
= new ArrayList
<>(Arrays
.asList(config
759 .getStringList(sectionparent
.name
, null, name
)));
760 entries
.add(Math
.max(index
, 0), newValue
);
761 config
.setStringList(sectionparent
.name
, null, name
, entries
);
763 // Arrays.asList returns a fixed-size list, so we need to copy
764 // over to a mutable list
765 entries
= new ArrayList
<>(Arrays
.asList(config
766 .getStringList(subsectionparent
.parent
.name
,
767 subsectionparent
.name
, name
)));
768 entries
.add(Math
.max(index
, 0), newValue
);
769 config
.setStringList(subsectionparent
.parent
.name
,
770 subsectionparent
.name
, name
, entries
);
775 Entry(SubSection parent
, String name
, String value
, int index
) {
776 this.sectionparent
= null;
777 this.subsectionparent
= parent
;
783 public void changeValue(String newValue
)
784 throws IllegalArgumentException
{
785 if (newValue
.length() == 0)
786 throw new IllegalArgumentException(
787 UIText
.ConfigurationEditorComponent_EmptyStringNotAllowed
);
788 Config config
= getConfig();
791 if (sectionparent
!= null)
792 config
.setString(sectionparent
.name
, null, name
, newValue
);
794 config
.setString(subsectionparent
.parent
.name
,
795 subsectionparent
.name
, name
, newValue
);
798 if (sectionparent
!= null) {
799 entries
= config
.getStringList(sectionparent
.name
, null,
801 entries
[index
] = newValue
;
802 config
.setStringList(sectionparent
.name
, null, name
,
803 Arrays
.asList(entries
));
805 entries
= config
.getStringList(
806 subsectionparent
.parent
.name
,
807 subsectionparent
.name
, name
);
808 entries
[index
] = newValue
;
809 config
.setStringList(subsectionparent
.parent
.name
,
810 subsectionparent
.name
, name
, Arrays
.asList(entries
));
815 private Config
getConfig() {
817 if (sectionparent
!= null)
818 config
= sectionparent
.parent
.config
;
820 config
= subsectionparent
.parent
.parent
.config
;
824 public void removeValue() {
825 Config config
= getConfig();
828 if (sectionparent
!= null)
829 config
.unset(sectionparent
.name
, null, name
);
831 config
.unset(subsectionparent
.parent
.name
,
832 subsectionparent
.name
, name
);
834 List
<String
> entries
;
835 if (sectionparent
!= null) {
836 // Arrays.asList returns a fixed-size list, so we need to
837 // copy over to a mutable list
838 entries
= new ArrayList
<>(Arrays
.asList(config
839 .getStringList(sectionparent
.name
, null, name
)));
841 entries
.remove(index
);
842 config
.setStringList(sectionparent
.name
, null, name
,
845 // Arrays.asList returns a fixed-size list, so we need to
846 // copy over to a mutable list
847 entries
= new ArrayList
<>(Arrays
.asList(config
848 .getStringList(subsectionparent
.parent
.name
,
849 subsectionparent
.name
, name
)));
850 // the list is fixed-size, so we have to copy over
851 entries
.remove(index
);
852 config
.setStringList(subsectionparent
.parent
.name
,
853 subsectionparent
.name
, name
, entries
);
859 public int hashCode() {
860 final int prime
= 31;
862 result
= prime
* result
+ index
;
863 result
= prime
* result
+ name
.hashCode();
864 result
= prime
* result
865 + ((sectionparent
== null) ?
0 : sectionparent
.hashCode());
868 + ((subsectionparent
== null) ?
0 : subsectionparent
874 public boolean equals(Object obj
) {
879 if (getClass() != obj
.getClass())
881 Entry other
= (Entry
) obj
;
882 // the index may change between 0 and -1 when values are added
883 if (index
!= other
.index
&& (index
> 0 || other
.index
> 0))
885 if (!name
.equals(other
.name
))
887 if (sectionparent
== null) {
888 if (other
.sectionparent
!= null)
890 } else if (!sectionparent
.equals(other
.sectionparent
))
892 if (subsectionparent
== null) {
893 if (other
.subsectionparent
!= null)
895 } else if (!subsectionparent
.equals(other
.subsectionparent
))
901 private static final class ConfigEditorLabelProvider
extends
902 BaseLabelProvider
implements ITableLabelProvider
, IFontProvider
{
903 private Font boldFont
= null;
905 private final Font defaultFont
;
907 public ConfigEditorLabelProvider(Font defaultFont
) {
908 this.defaultFont
= defaultFont
;
912 public Image
getColumnImage(Object element
, int columnIndex
) {
917 public String
getColumnText(Object element
, int columnIndex
) {
918 switch (columnIndex
) {
920 if (element
instanceof Section
)
921 return ((Section
) element
).name
;
922 if (element
instanceof SubSection
)
923 return ((SubSection
) element
).name
;
924 if (element
instanceof Entry
) {
925 Entry entry
= (Entry
) element
;
928 return entry
.name
+ "[" + entry
.index
+ "]"; //$NON-NLS-1$ //$NON-NLS-2$
932 if (element
instanceof Entry
)
933 return ((Entry
) element
).value
;
941 public Font
getFont(Object element
) {
942 if (element
instanceof Section
|| element
instanceof SubSection
)
943 return getBoldFont();
948 private Font
getBoldFont() {
949 if (boldFont
!= null)
951 FontData
[] data
= defaultFont
.getFontData();
952 for (int i
= 0; i
< data
.length
; i
++)
953 data
[i
].setStyle(data
[i
].getStyle() | SWT
.BOLD
);
955 boldFont
= new Font(Display
.getDefault(), data
);
960 public void dispose() {
961 if (boldFont
!= null)
967 private Shell
getShell() {
968 return shellProvider
.getShell();