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 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
8 * SPDX-License-Identifier: EPL-2.0
11 * Mathias Kinzler (SAP AG) - initial implementation
12 *******************************************************************************/
13 package org
.eclipse
.egit
.ui
.internal
.preferences
;
16 import java
.io
.IOException
;
17 import java
.util
.ArrayList
;
18 import java
.util
.Arrays
;
19 import java
.util
.Collections
;
20 import java
.util
.Comparator
;
21 import java
.util
.List
;
23 import java
.util
.StringTokenizer
;
25 import org
.eclipse
.core
.filesystem
.EFS
;
26 import org
.eclipse
.core
.filesystem
.IFileStore
;
27 import org
.eclipse
.core
.runtime
.Path
;
28 import org
.eclipse
.egit
.ui
.Activator
;
29 import org
.eclipse
.egit
.ui
.internal
.UIText
;
30 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
31 import org
.eclipse
.jface
.layout
.GridDataFactory
;
32 import org
.eclipse
.jface
.layout
.GridLayoutFactory
;
33 import org
.eclipse
.jface
.resource
.JFaceResources
;
34 import org
.eclipse
.jface
.viewers
.BaseLabelProvider
;
35 import org
.eclipse
.jface
.viewers
.CellEditor
;
36 import org
.eclipse
.jface
.viewers
.EditingSupport
;
37 import org
.eclipse
.jface
.viewers
.ICellEditorListener
;
38 import org
.eclipse
.jface
.viewers
.ICellEditorValidator
;
39 import org
.eclipse
.jface
.viewers
.IFontProvider
;
40 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
41 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
42 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
43 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
44 import org
.eclipse
.jface
.viewers
.TextCellEditor
;
45 import org
.eclipse
.jface
.viewers
.TreeViewer
;
46 import org
.eclipse
.jface
.viewers
.TreeViewerColumn
;
47 import org
.eclipse
.jface
.window
.IShellProvider
;
48 import org
.eclipse
.jface
.window
.SameShellProvider
;
49 import org
.eclipse
.jface
.window
.Window
;
50 import org
.eclipse
.jgit
.errors
.ConfigInvalidException
;
51 import org
.eclipse
.jgit
.lib
.Config
;
52 import org
.eclipse
.jgit
.lib
.StoredConfig
;
53 import org
.eclipse
.jgit
.storage
.file
.FileBasedConfig
;
54 import org
.eclipse
.osgi
.util
.NLS
;
55 import org
.eclipse
.swt
.SWT
;
56 import org
.eclipse
.swt
.events
.SelectionAdapter
;
57 import org
.eclipse
.swt
.events
.SelectionEvent
;
58 import org
.eclipse
.swt
.graphics
.Font
;
59 import org
.eclipse
.swt
.graphics
.FontData
;
60 import org
.eclipse
.swt
.graphics
.Image
;
61 import org
.eclipse
.swt
.layout
.GridLayout
;
62 import org
.eclipse
.swt
.widgets
.Button
;
63 import org
.eclipse
.swt
.widgets
.Composite
;
64 import org
.eclipse
.swt
.widgets
.Control
;
65 import org
.eclipse
.swt
.widgets
.Display
;
66 import org
.eclipse
.swt
.widgets
.Label
;
67 import org
.eclipse
.swt
.widgets
.Shell
;
68 import org
.eclipse
.swt
.widgets
.Text
;
69 import org
.eclipse
.swt
.widgets
.Tree
;
70 import org
.eclipse
.swt
.widgets
.TreeColumn
;
71 import org
.eclipse
.ui
.PartInitException
;
72 import org
.eclipse
.ui
.PlatformUI
;
73 import org
.eclipse
.ui
.editors
.text
.EditorsUI
;
74 import org
.eclipse
.ui
.ide
.FileStoreEditorInput
;
75 import org
.eclipse
.ui
.ide
.IDE
;
76 import org
.eclipse
.ui
.model
.WorkbenchAdapter
;
77 import org
.eclipse
.ui
.model
.WorkbenchContentProvider
;
80 * A reusable UI component to display and edit a Git configuration.
82 * Concrete subclasses that are interested in displaying error messages should
83 * override {@link #setErrorMessage(String)}
85 * TODO: do the changes in memory and offer methods to obtain dirty state, to
86 * save, and something like setDirty(boolean) to be implemented by subclasses so
87 * that proper save/revert can be implemented; we could also offer this for
88 * non-stored configurations
90 public class ConfigurationEditorComponent
{
92 private final static String DOT
= "."; //$NON-NLS-1$
94 private StoredConfig editableConfig
;
96 private final IShellProvider shellProvider
;
98 private final Composite parent
;
100 private final boolean useDialogFont
;
102 private Composite contents
;
104 private Button newValue
;
106 private Button remove
;
108 private TreeViewer tv
;
110 private Text location
;
112 private boolean editable
;
120 * to be used instead of the user configuration
121 * @param useDialogFont
122 * if <code>true</code>, the current dialog font is used
124 * horizontal margin to be used
126 public ConfigurationEditorComponent(Composite parent
, StoredConfig config
,
127 boolean useDialogFont
, int margin
) {
128 editableConfig
= config
;
129 this.shellProvider
= new SameShellProvider(parent
);
130 this.parent
= parent
;
131 this.useDialogFont
= useDialogFont
;
132 this.margin
= margin
;
135 void setConfig(FileBasedConfig config
) throws IOException
{
136 editableConfig
= config
;
138 editableConfig
.clear();
139 editableConfig
.load();
140 } catch (ConfigInvalidException e
) {
141 throw new IOException(e
.getMessage());
143 initControlsFromConfig();
147 * Saves and (in case of success) reloads the current configuration
149 * @throws IOException
151 public void save() throws IOException
{
152 editableConfig
.save();
154 initControlsFromConfig();
158 * Restores and (in case of success) reloads the current configuration
160 * @throws IOException
162 public void restore() throws IOException
{
164 editableConfig
.clear();
165 editableConfig
.load();
166 } catch (ConfigInvalidException e
) {
167 throw new IOException(e
.getMessage());
169 initControlsFromConfig();
173 * @return the control being created
175 public Control
createContents() {
176 final Composite main
= new Composite(parent
, SWT
.NONE
);
177 GridLayoutFactory
.fillDefaults().numColumns(2).margins(margin
, 0)
179 GridDataFactory
.fillDefaults().grab(true, true).applyTo(main
);
181 if (editableConfig
instanceof FileBasedConfig
) {
182 Composite locationPanel
= new Composite(main
, SWT
.NONE
);
183 GridLayout locationLayout
= new GridLayout(3, false);
184 locationLayout
.marginWidth
= 0;
185 locationPanel
.setLayout(locationLayout
);
186 GridDataFactory
.fillDefaults().grab(true, false).span(2, 1)
187 .applyTo(locationPanel
);
188 Label locationLabel
= new Label(locationPanel
, SWT
.NONE
);
190 .setText(UIText
.ConfigurationEditorComponent_ConfigLocationLabel
);
191 // GridDataFactory.fillDefaults().applyTo(locationLabel);
192 int locationStyle
= SWT
.BORDER
|SWT
.READ_ONLY
;
193 location
= new Text(locationPanel
, locationStyle
);
194 GridDataFactory
.fillDefaults().align(SWT
.FILL
, SWT
.CENTER
)
195 .grab(true, false).applyTo(location
);
196 Button openEditor
= new Button(locationPanel
, SWT
.PUSH
);
198 .setText(UIText
.ConfigurationEditorComponent_OpenEditorButton
);
200 .setToolTipText(UIText
.ConfigurationEditorComponent_OpenEditorTooltip
);
201 openEditor
.addSelectionListener(new SelectionAdapter() {
203 public void widgetSelected(SelectionEvent e
) {
204 IFileStore store
= EFS
.getLocalFileSystem().getStore(
205 new Path(((FileBasedConfig
) editableConfig
)
206 .getFile().getAbsolutePath()));
208 IDE
.openEditor(PlatformUI
.getWorkbench()
209 .getActiveWorkbenchWindow().getActivePage(),
210 new FileStoreEditorInput(store
),
211 EditorsUI
.DEFAULT_TEXT_EDITOR_ID
);
212 } catch (PartInitException ex
) {
213 Activator
.handleError(ex
.getMessage(), ex
, true);
218 .setEnabled(((FileBasedConfig
) editableConfig
).getFile() != null);
220 tv
= new TreeViewer(main
, SWT
.SINGLE
| SWT
.FULL_SELECTION
| SWT
.BORDER
);
221 Tree tree
= tv
.getTree();
222 GridDataFactory
.fillDefaults().hint(100, 60).grab(true, true)
224 TreeColumn key
= new TreeColumn(tree
, SWT
.NONE
);
225 key
.setText(UIText
.ConfigurationEditorComponent_KeyColumnHeader
);
228 final TextCellEditor editor
= new TextCellEditor(tree
);
229 editor
.setValidator(new ICellEditorValidator() {
232 public String
isValid(Object value
) {
233 String editedValue
= value
.toString();
234 return editedValue
.length() > 0 ?
null
235 : UIText
.ConfigurationEditorComponent_EmptyStringNotAllowed
;
238 editor
.addListener(new ICellEditorListener() {
241 public void editorValueChanged(boolean oldValidState
,
242 boolean newValidState
) {
243 setErrorMessage(editor
.getErrorMessage());
247 public void cancelEditor() {
248 setErrorMessage(null);
252 public void applyEditorValue() {
253 setErrorMessage(null);
257 TreeColumn value
= new TreeColumn(tree
, SWT
.NONE
);
258 value
.setText(UIText
.ConfigurationEditorComponent_ValueColumnHeader
);
260 new TreeViewerColumn(tv
, value
)
261 .setEditingSupport(new EditingSupport(tv
) {
264 protected void setValue(Object element
, Object newValue
) {
265 Entry entry
= (Entry
) element
;
266 if (!entry
.value
.equals(newValue
)) {
267 entry
.changeValue(newValue
.toString());
273 protected Object
getValue(Object element
) {
274 return ((Entry
) element
).value
;
278 protected CellEditor
getCellEditor(Object element
) {
283 protected boolean canEdit(Object element
) {
284 return editable
&& element
instanceof Entry
;
288 tv
.setContentProvider(new WorkbenchContentProvider());
291 defaultFont
= JFaceResources
.getDialogFont();
293 defaultFont
= JFaceResources
.getDefaultFont();
294 tv
.setLabelProvider(new ConfigEditorLabelProvider(defaultFont
));
296 tree
.setHeaderVisible(true);
297 tree
.setLinesVisible(true);
299 Composite buttonPanel
= new Composite(main
, SWT
.NONE
);
300 GridLayoutFactory
.fillDefaults().applyTo(buttonPanel
);
301 GridDataFactory
.fillDefaults().grab(false, false).applyTo(buttonPanel
);
302 newValue
= new Button(buttonPanel
, SWT
.PUSH
);
303 GridDataFactory
.fillDefaults().applyTo(newValue
);
304 newValue
.setText(UIText
.ConfigurationEditorComponent_AddButton
);
305 newValue
.addSelectionListener(new SelectionAdapter() {
307 public void widgetSelected(SelectionEvent e
) {
310 IStructuredSelection sel
= (IStructuredSelection
) tv
312 Object first
= sel
.getFirstElement();
313 if (first
instanceof Section
)
314 suggestedKey
= ((Section
) first
).name
+ DOT
;
315 else if (first
instanceof SubSection
) {
316 SubSection sub
= (SubSection
) first
;
317 suggestedKey
= sub
.parent
.name
+ DOT
+ sub
.name
+ DOT
;
318 } else if (first
instanceof Entry
) {
319 Entry entry
= (Entry
) first
;
320 if (entry
.sectionparent
!= null)
321 suggestedKey
= entry
.sectionparent
.name
+ DOT
;
323 suggestedKey
= entry
.subsectionparent
.parent
.name
+ DOT
324 + entry
.subsectionparent
.name
+ DOT
;
328 AddConfigEntryDialog dlg
= new AddConfigEntryDialog(getShell(),
330 if (dlg
.open() == Window
.OK
) {
331 String result
= dlg
.getKey();
332 if (result
== null) {
333 // bug in swt bot, see
334 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=472110
337 StringTokenizer st
= new StringTokenizer(result
, DOT
);
338 if (st
.countTokens() == 2) {
339 String sectionName
= st
.nextToken();
340 String entryName
= st
.nextToken();
341 Entry entry
= ((GitConfig
) tv
.getInput()).getEntry(
342 sectionName
, null, entryName
);
344 editableConfig
.setString(sectionName
, null,
345 entryName
, dlg
.getValue());
347 entry
.addValue(dlg
.getValue());
349 reveal(sectionName
, null, entryName
);
350 } else if (st
.countTokens() > 2) {
351 int n
= st
.countTokens();
352 String sectionName
= st
.nextToken();
353 StringBuilder b
= new StringBuilder(st
.nextToken());
354 for (int i
= 0; i
< n
- 3; i
++) {
356 b
.append(st
.nextToken());
358 String subSectionName
= b
.toString();
359 String entryName
= st
.nextToken();
360 Entry entry
= ((GitConfig
) tv
.getInput()).getEntry(
361 sectionName
, subSectionName
, entryName
);
363 editableConfig
.setString(sectionName
,
364 subSectionName
, entryName
, dlg
.getValue());
366 entry
.addValue(dlg
.getValue());
368 reveal(sectionName
, subSectionName
, entryName
);
372 UIText
.ConfigurationEditorComponent_WrongNumberOfTokensMessage
,
378 remove
= new Button(buttonPanel
, SWT
.PUSH
);
379 GridDataFactory
.fillDefaults().applyTo(remove
);
380 remove
.setText(UIText
.ConfigurationEditorComponent_RemoveButton
);
381 remove
.setToolTipText(UIText
.ConfigurationEditorComponent_RemoveTooltip
);
382 remove
.addSelectionListener(new SelectionAdapter() {
384 public void widgetSelected(SelectionEvent e
) {
385 IStructuredSelection sel
= (IStructuredSelection
) tv
387 Object first
= sel
.getFirstElement();
388 if (first
instanceof Section
) {
389 Section section
= (Section
) first
;
393 UIText
.ConfigurationEditorComponent_RemoveSectionTitle
,
395 UIText
.ConfigurationEditorComponent_RemoveSectionMessage
,
397 editableConfig
.unsetSection(section
.name
, null);
400 } else if (first
instanceof SubSection
) {
401 SubSection section
= (SubSection
) first
;
405 UIText
.ConfigurationEditorComponent_RemoveSubsectionTitle
,
407 UIText
.ConfigurationEditorComponent_RemoveSubsectionMessage
,
408 section
.parent
.name
+ DOT
410 editableConfig
.unsetSection(section
.parent
.name
,
414 } else if (first
instanceof Entry
) {
415 ((Entry
) first
).removeValue();
419 super.widgetSelected(e
);
423 tv
.addSelectionChangedListener(new ISelectionChangedListener() {
425 public void selectionChanged(SelectionChangedEvent event
) {
430 initControlsFromConfig();
436 * @return the composite containing all the controls
438 public Composite
getContents() {
442 private boolean isWriteable(final File f
) {
451 // no file, can we create one
452 for (File d
= f
.getParentFile(); d
!= null; d
= d
.getParentFile())
464 private void initControlsFromConfig() {
466 editableConfig
.load();
467 tv
.setInput(new GitConfig(editableConfig
));
469 if (editableConfig
instanceof FileBasedConfig
) {
470 FileBasedConfig fileConfig
= (FileBasedConfig
) editableConfig
;
471 File configFile
= fileConfig
.getFile();
472 if (configFile
!= null)
473 if (isWriteable(configFile
))
474 location
.setText(configFile
.getPath());
477 .bind(UIText
.ConfigurationEditorComponent_ReadOnlyLocationFormat
,
478 configFile
.getPath()));
482 location
.setText(UIText
.ConfigurationEditorComponent_NoConfigLocationKnown
);
486 } catch (IOException e
) {
487 Activator
.handleError(e
.getMessage(), e
, true);
488 } catch (ConfigInvalidException e
) {
489 Activator
.handleError(e
.getMessage(), e
, true);
497 * the error message to display
499 protected void setErrorMessage(String message
) {
500 // the default implementation does nothing
507 protected void setDirty(boolean dirty
) {
508 // the default implementation does nothing
511 private void updateEnablement() {
512 remove
.setEnabled(editable
&& !tv
.getSelection().isEmpty());
513 newValue
.setEnabled(editable
);
516 private void markDirty() {
518 ((GitConfig
) tv
.getInput()).refresh();
522 private void reveal(String sectionName
, String subSectionName
,
524 Entry entry
= ((GitConfig
) tv
.getInput()).getEntry(sectionName
,
525 subSectionName
, entryName
);
531 private final static class GitConfig
extends WorkbenchAdapter
{
533 private final Config config
;
535 private Section
[] children
;
537 GitConfig(Config config
) {
538 this.config
= config
;
541 GitConfig
refresh() {
547 public Object
[] getChildren(Object o
) {
548 if (children
== null)
549 if (config
!= null) {
550 List
<Section
> sections
= new ArrayList
<>();
551 Set
<String
> sectionNames
= config
.getSections();
552 for (String sectionName
: sectionNames
)
553 sections
.add(new Section(this, sectionName
));
554 Collections
.sort(sections
, new Comparator
<Section
>() {
557 public int compare(Section o1
, Section o2
) {
558 return o1
.name
.compareTo(o2
.name
);
561 children
= sections
.toArray(new Section
[0]);
563 children
= new Section
[0];
567 public Entry
getEntry(String sectionName
, String subsectionName
,
569 for (Object child
: getChildren(this)) {
570 Section section
= (Section
) child
;
571 if (sectionName
.equals(section
.name
))
572 return section
.getEntry(subsectionName
, entryName
);
578 private final static class Section
extends WorkbenchAdapter
{
579 private final String name
;
581 private final GitConfig parent
;
583 private Object
[] children
;
585 Section(GitConfig parent
, String name
) {
586 this.parent
= parent
;
591 public int hashCode() {
592 final int prime
= 31;
594 result
= prime
* result
+ name
.hashCode();
599 public boolean equals(Object obj
) {
604 if (getClass() != obj
.getClass())
606 Section other
= (Section
) obj
;
607 if (!name
.equals(other
.name
))
613 public Object
getParent(Object object
) {
618 public Object
[] getChildren(Object o
) {
619 if (children
== null) {
620 List
<Object
> allChildren
= new ArrayList
<>();
621 Set
<String
> subSectionNames
= parent
.config
622 .getSubsections(name
);
623 for (String subSectionName
: subSectionNames
)
624 allChildren
.add(new SubSection(parent
.config
, this,
627 Set
<String
> entryNames
= parent
.config
.getNames(name
);
628 for (String entryName
: entryNames
) {
629 String
[] values
= parent
.config
.getStringList(name
, null,
631 if (values
.length
== 1)
632 allChildren
.add(new Entry(this, entryName
, values
[0],
636 for (String value
: values
)
637 allChildren
.add(new Entry(this, entryName
, value
,
641 children
= allChildren
.toArray();
647 public String
getLabel(Object o
) {
651 public Entry
getEntry(String subsectionName
, String entryName
) {
652 if (subsectionName
!= null) {
653 for (Object child
: getChildren(this))
654 if (child
instanceof SubSection
655 && ((SubSection
) child
).name
.equals(subsectionName
))
656 return ((SubSection
) child
).getEntry(entryName
);
658 for (Object child
: getChildren(this))
659 if (child
instanceof Entry
660 && ((Entry
) child
).name
.equals(entryName
))
661 return (Entry
) child
;
666 private final static class SubSection
extends WorkbenchAdapter
{
668 private final Config config
;
670 private final Section parent
;
672 private final String name
;
674 private Entry
[] children
;
676 SubSection(Config config
, Section parent
, String name
) {
677 this.config
= config
;
678 this.parent
= parent
;
683 public int hashCode() {
684 final int prime
= 31;
686 result
= prime
* result
+ name
.hashCode();
687 result
= prime
* result
+ parent
.hashCode();
692 public boolean equals(Object obj
) {
697 if (getClass() != obj
.getClass())
699 SubSection other
= (SubSection
) obj
;
700 if (!name
.equals(other
.name
))
702 if (!parent
.equals(other
.parent
))
708 public Object
[] getChildren(Object o
) {
709 if (children
== null) {
710 List
<Entry
> entries
= new ArrayList
<>();
711 Set
<String
> entryNames
= config
.getNames(parent
.name
, name
);
712 for (String entryName
: entryNames
) {
713 String
[] values
= config
.getStringList(parent
.name
, name
,
715 if (values
.length
== 1)
716 entries
.add(new Entry(this, entryName
, values
[0], -1));
719 for (String value
: values
)
720 entries
.add(new Entry(this, entryName
, value
,
724 children
= entries
.toArray(new Entry
[0]);
730 public String
getLabel(Object o
) {
735 public Object
getParent(Object object
) {
739 public Entry
getEntry(String entryName
) {
740 for (Object child
: getChildren(this))
741 if (entryName
.equals(((Entry
) child
).name
))
742 return (Entry
) child
;
747 private final static class Entry
extends WorkbenchAdapter
{
749 private final Section sectionparent
;
751 private final SubSection subsectionparent
;
753 private final String name
;
755 private final String value
;
757 private final int index
;
759 Entry(Section parent
, String name
, String value
, int index
) {
760 this.sectionparent
= parent
;
761 this.subsectionparent
= null;
767 public void addValue(String newValue
) {
768 if (newValue
.length() == 0)
769 throw new IllegalArgumentException(
770 UIText
.ConfigurationEditorComponent_EmptyStringNotAllowed
);
771 Config config
= getConfig();
773 List
<String
> entries
;
774 if (sectionparent
!= null) {
775 // Arrays.asList returns a fixed-size list, so we need to copy
776 // over to a mutable list
777 entries
= new ArrayList
<>(Arrays
.asList(config
778 .getStringList(sectionparent
.name
, null, name
)));
779 entries
.add(Math
.max(index
, 0), newValue
);
780 config
.setStringList(sectionparent
.name
, null, name
, entries
);
782 // Arrays.asList returns a fixed-size list, so we need to copy
783 // over to a mutable list
784 entries
= new ArrayList
<>(Arrays
.asList(config
785 .getStringList(subsectionparent
.parent
.name
,
786 subsectionparent
.name
, name
)));
787 entries
.add(Math
.max(index
, 0), newValue
);
788 config
.setStringList(subsectionparent
.parent
.name
,
789 subsectionparent
.name
, name
, entries
);
794 Entry(SubSection parent
, String name
, String value
, int index
) {
795 this.sectionparent
= null;
796 this.subsectionparent
= parent
;
802 public void changeValue(String newValue
)
803 throws IllegalArgumentException
{
804 if (newValue
.length() == 0)
805 throw new IllegalArgumentException(
806 UIText
.ConfigurationEditorComponent_EmptyStringNotAllowed
);
807 Config config
= getConfig();
810 if (sectionparent
!= null)
811 config
.setString(sectionparent
.name
, null, name
, newValue
);
813 config
.setString(subsectionparent
.parent
.name
,
814 subsectionparent
.name
, name
, newValue
);
817 if (sectionparent
!= null) {
818 entries
= config
.getStringList(sectionparent
.name
, null,
820 entries
[index
] = newValue
;
821 config
.setStringList(sectionparent
.name
, null, name
,
822 Arrays
.asList(entries
));
824 entries
= config
.getStringList(
825 subsectionparent
.parent
.name
,
826 subsectionparent
.name
, name
);
827 entries
[index
] = newValue
;
828 config
.setStringList(subsectionparent
.parent
.name
,
829 subsectionparent
.name
, name
, Arrays
.asList(entries
));
834 private Config
getConfig() {
836 if (sectionparent
!= null)
837 config
= sectionparent
.parent
.config
;
839 config
= subsectionparent
.parent
.parent
.config
;
843 public void removeValue() {
844 Config config
= getConfig();
847 if (sectionparent
!= null)
848 config
.unset(sectionparent
.name
, null, name
);
850 config
.unset(subsectionparent
.parent
.name
,
851 subsectionparent
.name
, name
);
853 List
<String
> entries
;
854 if (sectionparent
!= null) {
855 // Arrays.asList returns a fixed-size list, so we need to
856 // copy over to a mutable list
857 entries
= new ArrayList
<>(Arrays
.asList(config
858 .getStringList(sectionparent
.name
, null, name
)));
860 entries
.remove(index
);
861 config
.setStringList(sectionparent
.name
, null, name
,
864 // Arrays.asList returns a fixed-size list, so we need to
865 // copy over to a mutable list
866 entries
= new ArrayList
<>(Arrays
.asList(config
867 .getStringList(subsectionparent
.parent
.name
,
868 subsectionparent
.name
, name
)));
869 // the list is fixed-size, so we have to copy over
870 entries
.remove(index
);
871 config
.setStringList(subsectionparent
.parent
.name
,
872 subsectionparent
.name
, name
, entries
);
878 public int hashCode() {
879 final int prime
= 31;
881 result
= prime
* result
+ index
;
882 result
= prime
* result
+ name
.hashCode();
883 result
= prime
* result
884 + ((sectionparent
== null) ?
0 : sectionparent
.hashCode());
887 + ((subsectionparent
== null) ?
0 : subsectionparent
893 public boolean equals(Object obj
) {
898 if (getClass() != obj
.getClass())
900 Entry other
= (Entry
) obj
;
901 // the index may change between 0 and -1 when values are added
902 if (index
!= other
.index
&& (index
> 0 || other
.index
> 0))
904 if (!name
.equals(other
.name
))
906 if (sectionparent
== null) {
907 if (other
.sectionparent
!= null)
909 } else if (!sectionparent
.equals(other
.sectionparent
))
911 if (subsectionparent
== null) {
912 if (other
.subsectionparent
!= null)
914 } else if (!subsectionparent
.equals(other
.subsectionparent
))
920 public Object
getParent(Object object
) {
921 if (sectionparent
!= null)
922 return sectionparent
;
924 return subsectionparent
;
928 private static final class ConfigEditorLabelProvider
extends
929 BaseLabelProvider
implements ITableLabelProvider
, IFontProvider
{
930 private Font boldFont
= null;
932 private final Font defaultFont
;
934 public ConfigEditorLabelProvider(Font defaultFont
) {
935 this.defaultFont
= defaultFont
;
939 public Image
getColumnImage(Object element
, int columnIndex
) {
944 public String
getColumnText(Object element
, int columnIndex
) {
945 switch (columnIndex
) {
947 if (element
instanceof Section
)
948 return ((Section
) element
).name
;
949 if (element
instanceof SubSection
)
950 return ((SubSection
) element
).name
;
951 if (element
instanceof Entry
) {
952 Entry entry
= (Entry
) element
;
955 return entry
.name
+ "[" + entry
.index
+ "]"; //$NON-NLS-1$ //$NON-NLS-2$
959 if (element
instanceof Entry
)
960 return ((Entry
) element
).value
;
968 public Font
getFont(Object element
) {
969 if (element
instanceof Section
|| element
instanceof SubSection
)
970 return getBoldFont();
975 private Font
getBoldFont() {
976 if (boldFont
!= null)
978 FontData
[] data
= defaultFont
.getFontData();
979 for (int i
= 0; i
< data
.length
; i
++)
980 data
[i
].setStyle(data
[i
].getStyle() | SWT
.BOLD
);
982 boldFont
= new Font(Display
.getDefault(), data
);
987 public void dispose() {
988 if (boldFont
!= null)
994 private Shell
getShell() {
995 return shellProvider
.getShell();