Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Mollik2018-02-23 08:38:41 -0500
committerRalf Mollik2018-02-23 08:38:41 -0500
commit677268317a6c09fe8bada16d91f0d13a317b33c7 (patch)
tree93266d3b626ac55078eb1d1749824f8e0734448c
downloadorg.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi-677268317a6c09fe8bada16d91f0d13a317b33c7.tar.gz
org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi-677268317a6c09fe8bada16d91f0d13a317b33c7.tar.xz
org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi-677268317a6c09fe8bada16d91f0d13a317b33c7.zip
initial checkin
-rw-r--r--.gitignore37
-rw-r--r--.osbp.releng.dependency.external0
-rw-r--r--.project22
-rw-r--r--.settings/org.eclipse.core.resources.prefs2
-rw-r--r--.settings/org.eclipse.m2e.core.prefs4
-rw-r--r--LICENSE.txt161
-rw-r--r--jenkins.build.config.xml20
-rw-r--r--license.html109
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.gitignore1
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.project34
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.core.resources.prefs2
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.m2e.core.prefs4
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.xtend.core.Xtend.prefs10
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/LICENSE.txt161
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/build.properties6
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/feature.properties169
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/feature.xml35
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/license.html164
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/pom.xml90
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/src/main/javadoc/README.txt1
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/src/overview.html13
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.classpath7
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.gitignore2
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.project51
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.core.resources.prefs2
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.jdt.core.prefs7
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.m2e.core.prefs4
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.xtend.core.Xtend.prefs10
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/LICENSE.txt161
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/META-INF/MANIFEST.MF20
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/build.properties12
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/license.html109
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/pom.xml94
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/Activator.java56
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/imageSelector/ISItem.java246
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/imageSelector/ImageSelector.java900
-rw-r--r--org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/widgets/ImageSelectorDialog.java196
-rw-r--r--org.mihalis.opal/.classpath9
-rw-r--r--org.mihalis.opal/.gitignore2
-rw-r--r--org.mihalis.opal/.project51
-rw-r--r--org.mihalis.opal/.settings/org.eclipse.core.resources.prefs7
-rw-r--r--org.mihalis.opal/.settings/org.eclipse.jdt.core.prefs297
-rw-r--r--org.mihalis.opal/.settings/org.eclipse.jdt.ui.prefs62
-rw-r--r--org.mihalis.opal/.settings/org.eclipse.m2e.core.prefs5
-rw-r--r--org.mihalis.opal/.settings/org.eclipse.xtend.core.Xtend.prefs11
-rw-r--r--org.mihalis.opal/LICENSE.txt161
-rw-r--r--org.mihalis.opal/META-INF/MANIFEST.MF54
-rw-r--r--org.mihalis.opal/README.md75
-rw-r--r--org.mihalis.opal/build.properties9
-rw-r--r--org.mihalis.opal/lib/swt.jarbin0 -> 1758962 bytes
-rw-r--r--org.mihalis.opal/license.html109
-rw-r--r--org.mihalis.opal/pom.xml50
-rw-r--r--org.mihalis.opal/src/images/arrowGreenRight.pngbin0 -> 3526 bytes
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/Activator.java57
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/OpalItem.java204
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/angles/AngleSlider.java326
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/breadcrumb/Breadcrumb.java396
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/breadcrumb/BreadcrumbItem.java1006
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/brushedMetalComposite/BrushedMetalComposite.java428
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/Calculator.java156
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorButtonsComposite.java489
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorCombo.java475
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorEngine.java355
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/DivideByZeroException.java36
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/checkBoxGroup/CheckBoxGroup.java360
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/columns/ColumnBrowserWidget.java771
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/columns/ColumnItem.java426
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicColumnData.java242
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLength.java82
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLengthFormat.java47
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLengthMeasure.java58
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTable.java168
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumn.java111
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumnLayout.java246
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTreeColumnLayout.java211
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/flatButton/FlatButton.java664
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/gradientComposite/GradientComposite.java148
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/header/Header.java566
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/heapManager/HeapManager.java321
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/horizontalSpinner/HorizontalSpinner.java1161
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ISItem.java202
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelector.java679
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/infinitePanel/InfiniteProgressPanel.java665
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DLItem.java144
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DualList.java1858
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/SelectionChangeEvent.java69
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/SelectionChangeListener.java39
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/Launcher.java451
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/LauncherItem.java38
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/LauncherLabel.java371
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/login/LoginDialog.java576
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/login/LoginDialogVerifier.java30
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoice.java1336
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceDefaultLabelProvider.java31
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceLabelProvider.java26
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceSelectionListener.java72
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/notify/Notifier.java350
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/notify/NotifierColors.java46
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/notify/NotifierColorsFactory.java76
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/AbstractButtonRenderer.java532
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/ButtonConfiguration.java175
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/ButtonRenderer.java82
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/DefaultButtonRenderer.java74
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/GreenButtonRenderer.java74
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/OButton.java653
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/OrangeButtonRenderer.java74
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/PurpleButtonRenderer.java75
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/RedButtonRenderer.java74
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/ChoiceItem.java62
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/ChoiceWidget.java319
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/Dialog.java592
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/DialogArea.java175
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/FooterArea.java611
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/MessageArea.java690
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/panels/BlurredPanel.java170
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/panels/DarkPanel.java158
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWContainer.java44
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWGroup.java192
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWRow.java160
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWRowGroup.java95
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWTab.java133
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWTabContainer.java208
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PreferenceWindow.java340
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/ValueAndAssociatedWidgets.java93
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfEquals.java49
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfNotEquals.java49
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfTrue.java49
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/Enabler.java60
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWButton.java70
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWCheckbox.java82
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWChooser.java85
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWColorChooser.java132
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWCombo.java118
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWDirectoryChooser.java84
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFileChooser.java81
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFloatText.java124
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFontChooser.java105
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWIntegerText.java94
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWLabel.java92
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWPasswordText.java79
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWRadio.java107
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWScale.java102
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWSeparator.java83
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWSpinner.java96
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWStringText.java78
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWText.java83
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWTextarea.java82
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWURLText.java114
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWWidget.java317
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/BaseFocusControlListener.java187
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/CComboFocusControlListener.java78
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/ComboFocusControlListener.java83
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/FocusControlListenerFactory.java49
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/PromptSupport.java247
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/StyledTextFocusControlListener.java87
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/TextFocusControlListener.java85
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/AbstractPTWidget.java267
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTProperty.java233
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTPropertyChangeListener.java26
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidget.java63
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetFactory.java35
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetTable.java203
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetTree.java198
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PropertyTable.java311
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTBaseTextEditor.java111
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTCheckboxEditor.java96
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTChooserEditor.java215
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTColorEditor.java100
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTComboEditor.java126
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDateEditor.java102
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDimensionEditor.java110
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDirectoryEditor.java78
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTEditor.java35
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFileEditor.java77
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFloatEditor.java95
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFontEditor.java93
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTInsetsEditor.java138
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTIntegerEditor.java74
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTPasswordEditor.java51
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTRectangleEditor.java137
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTSpinnerEditor.java105
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTStringEditor.java43
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTURLEditor.java73
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTWindowEditor.java169
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/rangeSlider/RangeSlider.java1140
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/roundedToolbar/RoundedToolItem.java1005
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/roundedToolbar/RoundedToolbar.java431
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/starRating/Star.java146
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/starRating/StarRating.java514
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/switchButton/SwitchButton.java878
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/CPUUsageSample.java82
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/HeapMemorySample.java85
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/PhysicalMemorySample.java80
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/Sample.java33
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleFactory.java81
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleIdentifier.java26
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleWrapper.java218
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SystemMonitor.java518
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/ThreadsUsageSample.java79
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/textAssist/TextAssist.java985
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/textAssist/TextAssistContentProvider.java51
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/tipOfTheDay/TipOfTheDay.java564
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/titledSeparator/TitledSeparator.java316
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/DownUpAppearTransition.java40
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/DownUpTransition.java39
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/HorizontalTransition.java94
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/LeftRightAppearTransition.java41
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/LeftRightTransition.java41
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/NoTransition.java34
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/RightLeftAppearTransition.java41
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/RightLeftTransition.java41
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TRANSITIONS.java36
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/Transition.java28
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TransitionComposite.java285
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TransitionFactory.java49
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/UpDownAppearTransition.java40
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/UpDownTransition.java33
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/VerticalTransition.java92
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/utils/AdvancedPath.java160
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/utils/FileToolbox.java50
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/utils/FixedSizeQueue.java142
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/utils/HTMLStyledTextParser.java514
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/utils/ReadOnlyStyledText.java78
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/utils/ResourceManager.java188
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/utils/SWTGraphicUtil.java573
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/utils/SimpleSelectionAdapter.java51
-rw-r--r--org.mihalis.opal/src/main/java/org/mihalis/opal/utils/StringUtil.java85
-rw-r--r--org.mihalis.opal/src/main/resources/images/angleBackground.pngbin0 -> 824 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/angleButtonFocus.pngbin0 -> 259 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/angleButtonFocusLost.pngbin0 -> 244 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/arrowGreenRight.pngbin0 -> 3526 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/arrow_down.pngbin0 -> 984 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/arrow_left.pngbin0 -> 980 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/arrow_right.pngbin0 -> 967 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/arrow_up.pngbin0 -> 970 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/category.pngbin0 -> 351 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/close.pngbin0 -> 351 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/columnArrow.pngbin0 -> 295 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/description.pngbin0 -> 493 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/double_down.pngbin0 -> 989 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/double_left.pngbin0 -> 988 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/double_right.pngbin0 -> 984 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/double_up.pngbin0 -> 977 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/fewerDetails.pngbin0 -> 933 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/h-slider-drag.pngbin0 -> 1057 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/h-slider-hover.pngbin0 -> 1057 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/h-slider-normal.pngbin0 -> 1055 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/h-slider-selected.pngbin0 -> 1041 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/information.pngbin0 -> 2745 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/light1.pngbin0 -> 9545 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/light2.pngbin0 -> 6542 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/moreDetails.pngbin0 -> 912 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/slider-drag.pngbin0 -> 1085 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/slider-hover.pngbin0 -> 1083 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/slider-normal.pngbin0 -> 1072 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/slider-selected.pngbin0 -> 430 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/sort.pngbin0 -> 532 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/stars/16.pngbin0 -> 583 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/stars/32.pngbin0 -> 1474 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/stars/focus16.pngbin0 -> 2641 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/stars/focus32.pngbin0 -> 4382 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/stars/mark-focus16.pngbin0 -> 2668 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/stars/mark-focus32.pngbin0 -> 4528 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/stars/mark16.pngbin0 -> 823 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/stars/mark32.pngbin0 -> 1745 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/images/trash.pngbin0 -> 688 bytes
-rw-r--r--org.mihalis.opal/src/main/resources/resources/opal.properties58
-rw-r--r--org.mihalis.opal/src/main/resources/resources/opal_de_DE.properties58
-rw-r--r--org.mihalis.opal/src/main/resources/resources/opal_es_ES.properties58
-rw-r--r--org.mihalis.opal/src/main/resources/resources/opal_fr_FR.properties58
-rw-r--r--org.mihalis.opal/src/main/resources/resources/opal_it_IT.properties58
-rw-r--r--org.mihalis.opal/src/main/resources/resources/opal_nl_NL.properties58
-rw-r--r--org.mihalis.opal/src/main/resources/resources/opal_pl_PL.properties58
-rw-r--r--org.mihalis.opal/src/main/resources/resources/opal_pt_BR.properties58
-rw-r--r--org.mihalis.opal/src/main/resources/resources/opal_zh_CN.properties58
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/angles/AngleSliderSnippet.java77
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/BreadcrumbSnippet.java132
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/add.pngbin0 -> 733 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/bell.pngbin0 -> 789 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/feed.pngbin0 -> 691 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/house.pngbin0 -> 806 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/script.pngbin0 -> 748 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/brushedMetalComposite/BrushedMetalCompositePlayer.java180
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/brushedMetalComposite/SnippetBrushedMetalComposite.java56
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/calculator/CalculatorComboSnippet.java58
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/calculator/CalculatorSnippet.java51
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/checkBoxGroup/SnippetCheckBoxGroup.java89
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/columns/ColumnsSnippet.java163
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumnsSnippet.java141
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/gradientComposite/SnippetGradientComposite.java59
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/header/HeaderSnippet.java76
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/header/configure.pngbin0 -> 5445 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/heapManager/HeapManagerSnippet.java56
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/horizontalSpinner/HorizontalSpinnerSnippet.java209
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/ImageSelectorSnippet.java57
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Black Eyed Peas.jpgbin0 -> 77000 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Coldplay.jpgbin0 -> 10060 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Foo Fighters.jpgbin0 -> 77291 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Gorillaz.jpgbin0 -> 46699 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Green Day.jpgbin0 -> 25521 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Moby.jpgbin0 -> 49250 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Norah Jones.jpgbin0 -> 15266 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Shivaree.jpgbin0 -> 47588 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Sin City.jpgbin0 -> 98472 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/infinitePanel/SnippetInfiniteProgressPanel.java125
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/DualListSnippet.java142
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/DualListTextSnippet.java126
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/austria.pngbin0 -> 439 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/belgium.pngbin0 -> 435 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/bulgaria.pngbin0 -> 445 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/cyprus.pngbin0 -> 461 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/czech.pngbin0 -> 468 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/denmark.pngbin0 -> 462 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/estonia.pngbin0 -> 403 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/finland.pngbin0 -> 483 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/france.pngbin0 -> 484 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/germany.pngbin0 -> 474 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/greece.pngbin0 -> 517 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/hungary.pngbin0 -> 396 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/ireland.pngbin0 -> 445 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/italy.pngbin0 -> 411 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/latvia.pngbin0 -> 454 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/lithuania.pngbin0 -> 459 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/luxembourg.pngbin0 -> 454 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/malta.pngbin0 -> 443 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/netherlands.pngbin0 -> 450 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/poland.pngbin0 -> 383 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/portugal.pngbin0 -> 519 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/romania.pngbin0 -> 458 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/slovakia.pngbin0 -> 491 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/slovenia.pngbin0 -> 553 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/spain.pngbin0 -> 469 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/sweden.pngbin0 -> 489 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/unitedkingdom.pngbin0 -> 668 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/LauncherSnippet.java74
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-address-book.pngbin0 -> 8559 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-calendar.pngbin0 -> 7374 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-presentation.pngbin0 -> 8617 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-spreadsheet.pngbin0 -> 8631 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/login/LoginDialogSnippet.java148
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/login/image.pngbin0 -> 18179 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/multiChoice/Country.java114
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/multiChoice/MultiChoiceSnippet.java234
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/notify/NotifierSnippet.java88
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/obutton/OButtonSnippet.java100
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/obutton/user.pngbin0 -> 687 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/opalDialog/OpalDialogSnippet.java427
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/opalDialog/warning.pngbin0 -> 804 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/panels/SnippetBlurredPanel.java107
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/panels/SnippetDarkPanel.java107
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/PreferenceWindowSnippet.java278
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/document.pngbin0 -> 2400 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/info.pngbin0 -> 565 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/openterm.pngbin0 -> 1630 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/printer.pngbin0 -> 1820 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/system.pngbin0 -> 2200 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/promptSupport/PromptSupportSnippet.java309
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/propertyTable/PropertyTableSnippet.java173
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/propertyTable/PropertyTableSnippetRefresh.java178
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/rangeSlider/RangeSliderSnippet.java348
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/RoundedToolbarSnippet.java194
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble1_b.pngbin0 -> 399 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble1_w.pngbin0 -> 299 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble2_b.pngbin0 -> 592 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble2_w.pngbin0 -> 522 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble3_b.pngbin0 -> 730 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble3_w.pngbin0 -> 724 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/email_b.pngbin0 -> 371 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/email_w.pngbin0 -> 370 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/starRating/StarRatingSnippet.java87
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/switchButton/SwitchButtonSnippet.java164
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/systemMonitor/RandomSample.java32
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/systemMonitor/SystemMonitorSnippet.java75
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/textAssist/TextAssistSnippet.java62
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/tipOfTheDay/TipOfTheDaySnippet.java109
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/titledSeparator/TitledSeparatorSnippet.java81
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/titledSeparator/user.pngbin0 -> 687 bytes
-rw-r--r--org.mihalis.opal/src/test/java/org/mihalis/opal/transitionComposite/TransitionCompositeSnippet.java167
-rw-r--r--pom.xml111
379 files changed, 48936 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b9f0a46
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,37 @@
+**/bin/
+**/target/
+**._trace
+**git.properties
+**/target/
+**/.metadata/
+
+**/emf-gen/**/.gitignore
+**/src-gen/**/.gitignore
+**/git.properties
+**/*.java._trace
+**/*.log
+**/*.log.properties
+
+**/bin/
+**/build/
+*.class
+*.ctrl
+**/Debug/
+.DS_Store
+*.ear
+*.war
+
+**/*.actionbin
+**/*.blipbin
+**/*.chartbin
+**/*.cubebin
+**/*.datatypebin
+**/*.dtobin
+**/*.entitybin
+**/*.servicebin
+**/*.tablebin
+**/*.uibin
+**/*.uisemanticbin
+**/*.xtendbin
+**/*.xtextbin
+
diff --git a/.osbp.releng.dependency.external b/.osbp.releng.dependency.external
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.osbp.releng.dependency.external
diff --git a/.project b/.project
new file mode 100644
index 0000000..ffccdf9
--- /dev/null
+++ b/.project
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.aggregator</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.sonarlint.eclipse.core.sonarlintBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..ff42ad4
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,161 @@
+Eclipse Public License -v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION
+OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
+
+b) in the case of each subsequent Contributor:
+
+i) changes to the Program, and
+
+ii) additions to the Program;
+
+where such changes and/or additions to the Program originate from and are distributed by that particular Contributor.
+A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone
+acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate
+modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not
+derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of
+its Contribution alone or when combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute
+and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code
+form.
+
+b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the
+Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the
+combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such
+addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not
+apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
+
+c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no
+assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property
+rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity
+based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and
+licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property
+rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the
+Program, it is Recipient's responsibility to acquire that license before distributing the Program.
+
+d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to
+grant the copyright license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
+
+a) it complies with the terms and conditions of this Agreement; and
+
+b) its license agreement:
+
+i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including
+warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and
+fitness for a particular purpose;
+
+ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special,
+incidental and consequential damages, such as lost profits;
+
+iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any
+other party; and
+
+iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it
+in a reasonable manner on or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+a) it must be made available under this Agreement; and
+
+b) a copy of this Agreement must be included with each copy of the Program.
+
+Contributors may not remove or alter any copyright notices contained within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and
+the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes
+the Program in a commercial product offering should do so in a manner which does not create potential liability for
+other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor")
+against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions
+brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual
+property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the
+Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may
+ participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is
+then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties
+related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone.
+Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to
+those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result,
+the Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for
+determining the appropriateness of using and distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance
+with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or
+enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such
+provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit)
+alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such
+Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or
+conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such
+noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution
+of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses
+ granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement
+is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish
+new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the
+right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may
+assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the
+Agreement will be given a distinguishing version number. The Program (including Contributions) may always be
+distributed subject to the version of the Agreement under which it was received. In addition, after a new version of
+the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the
+new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
+the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or
+otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States
+of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause
+of action arose. Each party waives its rights to a jury trial in any resulting litigation. \ No newline at end of file
diff --git a/jenkins.build.config.xml b/jenkins.build.config.xml
new file mode 100644
index 0000000..2d2773b
--- /dev/null
+++ b/jenkins.build.config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--#======================================================================= -->
+<!--# Copyright (c) 2016 - Loetz GmbH&Co.KG -->
+<!--# All rights reserved. This program and the accompanying materials -->
+<!--# are made available under the terms of the Eclipse Public License v1.0 -->
+<!--# which accompanies this distribution, and is available at -->
+<!--# http://www.eclipse.org/legal/epl-v10.html -->
+<!--# -->
+<!--# Contributors: -->
+<!--# Christophe Loetz (Loetz GmbH&Co.KG) - initial API and implementation -->
+<!--#======================================================================= -->
+<!--# Module specific parameters for the Jenkins Job -->
+<!--#======================================================================= -->
+
+<jenkins>
+ <!-- DO NOT EDIT BELOW THIS LINE -->
+ <jenkins.build.dependencies>
+ <jenkins.build.dependency>org.eclipse.osbp.utils.themes.ui</jenkins.build.dependency>
+ </jenkins.build.dependencies>
+</jenkins>
diff --git a/license.html b/license.html
new file mode 100644
index 0000000..c33d45c
--- /dev/null
+++ b/license.html
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Foundation Software User Agreement</title>
+</head>
+
+<body lang="EN-US">
+<h2>Eclipse Foundation Software User Agreement</h2>
+<p>February 1, 2011</p>
+
+<h3>Usage Of Content</h3>
+
+<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+ (COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+ CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+ OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+ NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+ CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+
+<h3>Applicable Licenses</h3>
+
+<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
+ (&quot;EPL&quot;). A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+ For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
+ repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
+
+<ul>
+ <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
+ <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
+ <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;. Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
+ and/or Fragments associated with that Feature.</li>
+ <li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
+</ul>
+
+<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
+Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and Feature Licenses may be located in any directory of a Download or Module
+including, but not limited to the following locations:</p>
+
+<ul>
+ <li>The top-level (root) directory</li>
+ <li>Plug-in and Fragment directories</li>
+ <li>Inside Plug-ins and Fragments packaged as JARs</li>
+ <li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
+ <li>Feature directories</li>
+</ul>
+
+<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
+installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
+inform you where you can locate them. Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
+that directory.</p>
+
+<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+
+<ul>
+ <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
+ <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
+ <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
+ <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
+ <li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li>
+ <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
+</ul>
+
+<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+
+
+<h3>Use of Provisioning Technology</h3>
+
+<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
+ Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
+ other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
+ install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
+ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+ (&quot;Specification&quot;).</p>
+
+<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
+ applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
+ in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
+ Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+
+<ol>
+ <li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
+ on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
+ product.</li>
+ <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
+ accessed and copied to the Target Machine.</li>
+ <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
+ Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
+ Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
+ the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
+ indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
+</ol>
+
+<h3>Cryptography</h3>
+
+<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
+ another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
+ possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+
+<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
+</body>
+</html> \ No newline at end of file
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.gitignore b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.project b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.project
new file mode 100644
index 0000000..72a4a85
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.sonarlint.eclipse.core.sonarlintBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.core.resources.prefs b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.m2e.core.prefs b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.xtend.core.Xtend.prefs b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.xtend.core.Xtend.prefs
new file mode 100644
index 0000000..0933f8c
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/.settings/org.eclipse.xtend.core.Xtend.prefs
@@ -0,0 +1,10 @@
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/test/java.directory=src/test/generated-sources/xtend
+eclipse.preferences.version=1
+is_project_specific=true
+outlet.DEFAULT_OUTPUT.hideLocalSyntheticVariables=true
+outlet.DEFAULT_OUTPUT.installDslAsPrimarySource=false
+outlet.DEFAULT_OUTPUT.sourceFolder.emf-gen.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.sourceFolder.src-gen.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.sourceFolder.src.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.sourceFolder.xtend-gen.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.userOutputPerSourceFolder=true
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/LICENSE.txt b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/LICENSE.txt
new file mode 100644
index 0000000..ff42ad4
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/LICENSE.txt
@@ -0,0 +1,161 @@
+Eclipse Public License -v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION
+OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
+
+b) in the case of each subsequent Contributor:
+
+i) changes to the Program, and
+
+ii) additions to the Program;
+
+where such changes and/or additions to the Program originate from and are distributed by that particular Contributor.
+A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone
+acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate
+modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not
+derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of
+its Contribution alone or when combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute
+and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code
+form.
+
+b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the
+Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the
+combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such
+addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not
+apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
+
+c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no
+assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property
+rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity
+based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and
+licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property
+rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the
+Program, it is Recipient's responsibility to acquire that license before distributing the Program.
+
+d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to
+grant the copyright license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
+
+a) it complies with the terms and conditions of this Agreement; and
+
+b) its license agreement:
+
+i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including
+warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and
+fitness for a particular purpose;
+
+ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special,
+incidental and consequential damages, such as lost profits;
+
+iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any
+other party; and
+
+iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it
+in a reasonable manner on or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+a) it must be made available under this Agreement; and
+
+b) a copy of this Agreement must be included with each copy of the Program.
+
+Contributors may not remove or alter any copyright notices contained within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and
+the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes
+the Program in a commercial product offering should do so in a manner which does not create potential liability for
+other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor")
+against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions
+brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual
+property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the
+Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may
+ participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is
+then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties
+related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone.
+Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to
+those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result,
+the Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for
+determining the appropriateness of using and distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance
+with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or
+enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such
+provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit)
+alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such
+Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or
+conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such
+noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution
+of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses
+ granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement
+is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish
+new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the
+right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may
+assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the
+Agreement will be given a distinguishing version number. The Program (including Contributions) may always be
+distributed subject to the version of the Agreement under which it was received. In addition, after a new version of
+the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the
+new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
+the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or
+otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States
+of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause
+of action arose. Each party waives its rights to a jury trial in any resulting litigation. \ No newline at end of file
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/build.properties b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/build.properties
new file mode 100644
index 0000000..92fee67
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/build.properties
@@ -0,0 +1,6 @@
+bin.includes = feature.xml,\
+ feature.properties,\
+ license.html,\
+ LICENSE.txt
+src.includes = LICENSE.txt,\
+ license.html
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/feature.properties b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/feature.properties
new file mode 100644
index 0000000..5bdea67
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/feature.properties
@@ -0,0 +1,169 @@
+###############################################################################
+# Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany).
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Christophe Loetz (Loetz GmbH&Co.KG) - initial API and implementation
+###############################################################################
+# feature.properties
+# contains externalized strings for feature.xml
+# "%foo" in feature.xml corresponds to the key "foo" in this file
+# java.io.Properties file (ISO 8859-1 with "\" escapes)
+# This file should be translated.
+
+# "featureName" property - name of the feature
+featureName =OSBP org.mihalis.opal.imageSelector.osgi
+
+# "providerName" property - name of the company that provides the feature
+providerName=Eclipse OSBP
+
+# "description" property - description of the feature
+description=This feature provides the bundles for the OSBP org.mihalis.opal.imageSelector.osgi.
+
+# "updateSiteName" property - label for the update site
+updateSiteName=
+
+# "copyright" property - text of the "Feature Update Copyright"
+copyright=\
+Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany).\n\
+All rights reserved. This program and the accompanying materials\n\
+are made available under the terms of the Eclipse Public License v1.0\n\
+which accompanies this distribution, and is available at\n\
+http://www.eclipse.org/legal/epl-v10.html\n\
+\n
+################ end of copyright property ####################################
+
+# "licenseURL" property - URL of the "Feature License"
+# do not translate value - just change to point to a locale-specific HTML page
+licenseURL=license.html
+
+# "license" property - text of the "Feature Update License"
+# should be plain text version of license agreement pointed to be "licenseURL"
+license=\
+Eclipse Foundation Software User Agreement\n\
+February 1, 2011\n\
+\n\
+Usage Of Content\n\
+\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
+OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
+USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
+AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
+NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU\n\
+AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
+AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
+OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
+OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+\n\
+Applicable Licenses\n\
+\n\
+Unless otherwise indicated, all Content made available by the\n\
+Eclipse Foundation is provided to you under the terms and conditions of\n\
+the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
+provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
+For purposes of the EPL, "Program" will mean the Content.\n\
+\n\
+Content includes, but is not limited to, source code, object code,\n\
+documentation and other files maintained in the Eclipse Foundation source code\n\
+repository ("Repository") in software modules ("Modules") and made available\n\
+as downloadable archives ("Downloads").\n\
+\n\
+ - Content may be structured and packaged into modules to facilitate delivering,\n\
+ extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
+ plug-in fragments ("Fragments"), and features ("Features").\n\
+ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
+ in a directory named "plugins".\n\
+ - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
+ Each Feature may be packaged as a sub-directory in a directory named "features".\n\
+ Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
+ numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
+ - Features may also include other Features ("Included Features"). Within a Feature, files\n\
+ named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+\n\
+The terms and conditions governing Plug-ins and Fragments should be\n\
+contained in files named "about.html" ("Abouts"). The terms and\n\
+conditions governing Features and Included Features should be contained\n\
+in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
+Licenses may be located in any directory of a Download or Module\n\
+including, but not limited to the following locations:\n\
+\n\
+ - The top-level (root) directory\n\
+ - Plug-in and Fragment directories\n\
+ - Inside Plug-ins and Fragments packaged as JARs\n\
+ - Sub-directories of the directory named "src" of certain Plug-ins\n\
+ - Feature directories\n\
+\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
+Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
+Update License") during the installation process. If the Feature contains\n\
+Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform\n\
+you where you can locate them. Feature Update Licenses may be found in\n\
+the "license" property of files named "feature.properties" found within a Feature.\n\
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
+terms and conditions (or references to such terms and conditions) that\n\
+govern your use of the associated Content in that directory.\n\
+\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
+TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
+SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+\n\
+ - Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+ - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
+ - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
+ - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
+ - Metro Link Public License 1.00 (available at http://www.opengroup.org/openmotif/supporters/metrolink/license.html)\n\
+ - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
+TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
+is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
+govern that particular Content.\n\
+\n\
+\n\Use of Provisioning Technology\n\
+\n\
+The Eclipse Foundation makes available provisioning software, examples of which include,\n\
+but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
+the purpose of allowing users to install software, documentation, information and/or\n\
+other materials (collectively "Installable Software"). This capability is provided with\n\
+the intent of allowing such users to install, extend and update Eclipse-based products.\n\
+Information about packaging Installable Software is available at\n\
+http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
+\n\
+You may use Provisioning Technology to allow other parties to install Installable Software.\n\
+You shall be responsible for enabling the applicable license agreements relating to the\n\
+Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
+in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
+making it available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the following:\n\
+\n\
+ 1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
+ the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
+ extending or updating the functionality of an Eclipse-based product.\n\
+ 2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
+ Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
+ 3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
+ govern the use of the Installable Software ("Installable Software Agreement") and such\n\
+ Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
+ with the Specification. Such Installable Software Agreement must inform the user of the\n\
+ terms and conditions that govern the Installable Software and must solicit acceptance by\n\
+ the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
+ indication of agreement by the user, the provisioning Technology will complete installation\n\
+ of the Installable Software.\n\
+\n\
+Cryptography\n\
+\n\
+Content may contain encryption software. The country in which you are\n\
+currently may have restrictions on the import, possession, and use,\n\
+and/or re-export to another country, of encryption software. BEFORE\n\
+using any encryption software, please check the country's laws,\n\
+regulations and policies concerning the import, possession, or use, and\n\
+re-export of encryption software, to see if this is permitted.\n\
+\n\
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
+########### end of license property ##########################################
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/feature.xml b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/feature.xml
new file mode 100644
index 0000000..3994254
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/feature.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature"
+ label="%featureName"
+ version="0.9.0.qualifier"
+ provider-name="%providerName"
+ plugin="org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi">
+
+ <description>
+ %description
+ </description>
+
+ <copyright>
+ %copyright
+ </copyright>
+
+ <license url="%licenseURL">
+ %license
+ </license>
+
+ <plugin
+ id="org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.mihalis.opal"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/license.html b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/license.html
new file mode 100644
index 0000000..6e579a5
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/license.html
@@ -0,0 +1,164 @@
+<!--?xml version="1.0" encoding="ISO-8859-1" ?-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>Eclipse Foundation Software User Agreement</title>
+</head>
+
+<body lang="EN-US">
+<h2>Eclipse Foundation Software User Agreement</h2>
+<p>February 1, 2011</p>
+
+<h3>Usage Of Content</h3>
+
+<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+ (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+ CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+ OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+ NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+ CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+
+<h3>Applicable Licenses</h3>
+
+<p>Unless otherwise indicated, all Content made available by the Eclipse
+ Foundation is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0
+ ("EPL"). A copy of the EPL is provided with this Content and is also
+ available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+ For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>Content includes, but is not limited to, source code, object code,
+documentation and other files maintained in the Eclipse Foundation
+source code
+ repository ("Repository") in software modules ("Modules") and made
+available as downloadable archives ("Downloads").</p>
+
+<ul>
+ <li>Content may be structured and packaged into modules to
+facilitate delivering, extending, and upgrading the Content. Typical
+modules may include plug-ins ("Plug-ins"), plug-in fragments
+("Fragments"), and features ("Features").</li>
+ <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&#8482; ARchive) in a directory named "plugins".</li>
+ <li>A Feature is a bundle of one or more Plug-ins and/or
+Fragments and associated material. Each Feature may be packaged as a
+sub-directory in a directory named "features". Within a Feature, files
+named "feature.xml" may contain a list of the names and version numbers
+of the Plug-ins
+ and/or Fragments associated with that Feature.</li>
+ <li>Features may also include other Features ("Included
+Features"). Within a Feature, files named "feature.xml" may contain a
+list of the names and version numbers of Included Features.</li>
+</ul>
+
+<p>The terms and conditions governing Plug-ins and Fragments should be
+contained in files named "about.html" ("Abouts"). The terms and
+conditions governing Features and
+Included Features should be contained in files named "license.html"
+("Feature Licenses"). Abouts and Feature Licenses may be located in any
+ directory of a Download or Module
+including, but not limited to the following locations:</p>
+
+<ul>
+ <li>The top-level (root) directory</li>
+ <li>Plug-in and Fragment directories</li>
+ <li>Inside Plug-ins and Fragments packaged as JARs</li>
+ <li>Sub-directories of the directory named "src" of certain Plug-ins</li>
+ <li>Feature directories</li>
+</ul>
+
+<p>Note: if a Feature made available by the Eclipse Foundation is
+installed using the Provisioning Technology (as defined below), you must
+ agree to a license ("Feature Update License") during the
+installation process. If the Feature contains Included Features, the
+Feature Update License should either provide you with the terms and
+conditions governing the Included Features or
+inform you where you can locate them. Feature Update Licenses may be
+found in the "license" property of files named "feature.properties"
+found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the
+terms and conditions (or references to such terms and conditions) that
+govern your use of the associated Content in
+that directory.</p>
+
+<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER
+TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.
+ SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+
+<ul>
+ <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
+ <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
+ <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
+ <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
+ <li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li>
+ <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
+</ul>
+
+<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND
+CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License,
+or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions
+govern that particular Content.</p>
+
+
+<h3>Use of Provisioning Technology</h3>
+
+<p>The Eclipse Foundation makes available provisioning software,
+examples of which include, but are not limited to, p2 and the Eclipse
+ Update Manager ("Provisioning Technology") for the purpose of
+allowing users to install software, documentation, information and/or
+ other materials (collectively "Installable Software"). This
+capability is provided with the intent of allowing such users to
+ install, extend and update Eclipse-based products. Information about
+packaging Installable Software is available at <a href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+ ("Specification").</p>
+
+<p>You may use Provisioning Technology to allow other parties to install
+ Installable Software. You shall be responsible for enabling the
+ applicable license agreements relating to the Installable Software to
+ be presented to, and accepted by, the users of the Provisioning
+Technology
+ in accordance with the Specification. By using Provisioning
+Technology in such a manner and making it available in accordance with
+the
+ Specification, you further acknowledge your agreement to, and the
+acquisition of all necessary rights to permit the following:</p>
+
+<ol>
+ <li>A series of actions may occur ("Provisioning Process") in
+which a user may execute the Provisioning Technology
+ on a machine ("Target Machine") with the intent of installing,
+extending or updating the functionality of an Eclipse-based
+ product.</li>
+ <li>During the Provisioning Process, the Provisioning Technology
+may cause third party Installable Software or a portion thereof to be
+ accessed and copied to the Target Machine.</li>
+ <li>Pursuant to the Specification, you will provide to the user
+the terms and conditions that govern the use of the Installable
+ Software ("Installable Software Agreement") and such Installable
+Software Agreement shall be accessed from the Target
+ Machine in accordance with the Specification. Such Installable
+Software Agreement must inform the user of the terms and conditions that
+ govern
+ the Installable Software and must solicit acceptance by the end
+user in the manner prescribed in such Installable Software Agreement.
+Upon such
+ indication of agreement by the user, the provisioning Technology
+will complete installation of the Installable Software.</li>
+</ol>
+
+<h3>Cryptography</h3>
+
+<p>Content may contain encryption software. The country in which you are
+ currently may have restrictions on the import, possession, and use,
+and/or re-export to
+ another country, of encryption software. BEFORE using any encryption
+software, please check the country's laws, regulations and policies
+concerning the import,
+ possession, or use, and re-export of encryption software, to see if
+this is permitted.</p>
+
+<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
+
+
+</body></html> \ No newline at end of file
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/pom.xml b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/pom.xml
new file mode 100644
index 0000000..3a06fe4
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/pom.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--#======================================================================= -->
+<!--# Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany). -->
+<!--# All rights reserved. This program and the accompanying materials -->
+<!--# are made available under the terms of the Eclipse Public License v1.0 -->
+<!--# which accompanies this distribution, and is available at -->
+<!--# http://www.eclipse.org/legal/epl-v10.html -->
+<!--# -->
+<!--# Contributors: -->
+<!--# Christophe Loetz (Loetz GmbH&Co.KG) - Initial implementation API and implementation -->
+<!--#======================================================================= -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi</groupId>
+ <artifactId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.aggregator</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <artifactId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature</artifactId>
+ <packaging>eclipse-feature</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.tycho.extras</groupId>
+ <artifactId>tycho-source-feature-plugin</artifactId>
+ <version>${tychoExtrasVersion}</version>
+ <executions>
+ <execution>
+ <id>source-feature</id>
+ <phase>package</phase>
+ <goals>
+ <goal>source-feature</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <labelSuffix> (source)</labelSuffix>
+ </configuration>
+ </plugin>
+ <plugin>
+ <!-- workaround while bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=398250
+ is not fixed -->
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>tycho-p2-plugin</artifactId>
+ <version>${tycho-version}</version>
+ <executions>
+ <execution>
+ <id>attached-p2-metadata</id>
+ <phase>package</phase>
+ <goals>
+ <goal>p2-metadata</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>javadoc-jar</id>
+ <phase>package</phase>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi</groupId>
+ <artifactId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi</groupId>
+ <artifactId>org.mihalis.opal</artifactId>
+ <version>1.0.3-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/src/main/javadoc/README.txt b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/src/main/javadoc/README.txt
new file mode 100644
index 0000000..831da7e
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/src/main/javadoc/README.txt
@@ -0,0 +1 @@
+Resource folder for javadoc resources. \ No newline at end of file
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/src/overview.html b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/src/overview.html
new file mode 100644
index 0000000..1034baa
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature/src/overview.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>OSBP Tools Graphical Entity</title>
+</head>
+<body>
+<p>The <strong>OSBP&nbsp;fork mihalis opal image selector </strong>contains the fork of the org.mihalis.opal implemented by Laurent CARON&nbsp;https://github.com/lcaron/opal.</p>
+
+<p>&nbsp;</p>
+
+<p>OSBP adds the OSGI capability and the&nbsp;bundles under org.eclipse.osbp.fork.mihalis.opal.imageSelector to be able to use it in the OSBP environment.</p>
+</body>
+</html>
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.classpath b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.classpath
new file mode 100644
index 0000000..cf36b56
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src/"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.gitignore b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.gitignore
new file mode 100644
index 0000000..92145bc
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.gitignore
@@ -0,0 +1,2 @@
+/bin/
+/target/ \ No newline at end of file
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.project b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.project
new file mode 100644
index 0000000..cfc4cc8
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.project
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.babel.editor.rbeBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.sonarlint.eclipse.core.sonarlintBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.babel.editor.rbeNature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.core.resources.prefs b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..0c68a61
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.m2e.core.prefs b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.xtend.core.Xtend.prefs b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.xtend.core.Xtend.prefs
new file mode 100644
index 0000000..0933f8c
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/.settings/org.eclipse.xtend.core.Xtend.prefs
@@ -0,0 +1,10 @@
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/test/java.directory=src/test/generated-sources/xtend
+eclipse.preferences.version=1
+is_project_specific=true
+outlet.DEFAULT_OUTPUT.hideLocalSyntheticVariables=true
+outlet.DEFAULT_OUTPUT.installDslAsPrimarySource=false
+outlet.DEFAULT_OUTPUT.sourceFolder.emf-gen.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.sourceFolder.src-gen.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.sourceFolder.src.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.sourceFolder.xtend-gen.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.userOutputPerSourceFolder=true
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/LICENSE.txt b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/LICENSE.txt
new file mode 100644
index 0000000..ff42ad4
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/LICENSE.txt
@@ -0,0 +1,161 @@
+Eclipse Public License -v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION
+OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
+
+b) in the case of each subsequent Contributor:
+
+i) changes to the Program, and
+
+ii) additions to the Program;
+
+where such changes and/or additions to the Program originate from and are distributed by that particular Contributor.
+A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone
+acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate
+modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not
+derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of
+its Contribution alone or when combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute
+and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code
+form.
+
+b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the
+Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the
+combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such
+addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not
+apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
+
+c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no
+assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property
+rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity
+based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and
+licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property
+rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the
+Program, it is Recipient's responsibility to acquire that license before distributing the Program.
+
+d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to
+grant the copyright license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
+
+a) it complies with the terms and conditions of this Agreement; and
+
+b) its license agreement:
+
+i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including
+warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and
+fitness for a particular purpose;
+
+ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special,
+incidental and consequential damages, such as lost profits;
+
+iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any
+other party; and
+
+iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it
+in a reasonable manner on or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+a) it must be made available under this Agreement; and
+
+b) a copy of this Agreement must be included with each copy of the Program.
+
+Contributors may not remove or alter any copyright notices contained within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and
+the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes
+the Program in a commercial product offering should do so in a manner which does not create potential liability for
+other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor")
+against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions
+brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual
+property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the
+Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may
+ participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is
+then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties
+related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone.
+Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to
+those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result,
+the Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for
+determining the appropriateness of using and distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance
+with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or
+enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such
+provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit)
+alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such
+Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or
+conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such
+noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution
+of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses
+ granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement
+is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish
+new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the
+right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may
+assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the
+Agreement will be given a distinguishing version number. The Program (including Contributions) may always be
+distributed subject to the version of the Agreement under which it was received. In addition, after a new version of
+the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the
+new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
+the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or
+otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States
+of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause
+of action arose. Each party waives its rights to a jury trial in any resulting litigation. \ No newline at end of file
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/META-INF/MANIFEST.MF b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..52b5969
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi
+Bundle-SymbolicName: org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi
+Bundle-Vendor: Eclipse OSBP
+Bundle-Version: 0.9.0.qualifier
+Bundle-ClassPath: .
+Export-Package: org.eclipse.osbp.fork.mihalis.opal.imageSelector,
+ org.eclipse.osbp.fork.mihalis.opal.widgets
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.swt;bundle-version="3.103.2",
+ org.eclipse.equinox.common,
+ org.eclipse.core.runtime,
+ org.eclipse.emf.common,
+ org.eclipse.osbp.gitinfo;bundle-version="[0.9.0,0.10.0)",
+ org.mihalis.opal;bundle-version="1.0.3",
+ org.slf4j.api;bundle-version="1.7.2"
+Bundle-ActivationPolicy: lazy
+Import-Package: org.apache.commons.io,
+ org.eclipse.osbp.utils.themes.ui
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/build.properties b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/build.properties
new file mode 100644
index 0000000..b0bfa0f
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/build.properties
@@ -0,0 +1,12 @@
+source.. = src/
+bin.includes = META-INF/,\
+ .,\
+ .classpath,\
+ .project,\
+ .settings/,\
+ LICENSE.txt,\
+ license.html
+output.. = target/classes
+src.includes = LICENSE.txt,\
+ license.html
+
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/license.html b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/license.html
new file mode 100644
index 0000000..c33d45c
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/license.html
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Foundation Software User Agreement</title>
+</head>
+
+<body lang="EN-US">
+<h2>Eclipse Foundation Software User Agreement</h2>
+<p>February 1, 2011</p>
+
+<h3>Usage Of Content</h3>
+
+<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+ (COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+ CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+ OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+ NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+ CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+
+<h3>Applicable Licenses</h3>
+
+<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
+ (&quot;EPL&quot;). A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+ For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
+ repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
+
+<ul>
+ <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
+ <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
+ <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;. Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
+ and/or Fragments associated with that Feature.</li>
+ <li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
+</ul>
+
+<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
+Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and Feature Licenses may be located in any directory of a Download or Module
+including, but not limited to the following locations:</p>
+
+<ul>
+ <li>The top-level (root) directory</li>
+ <li>Plug-in and Fragment directories</li>
+ <li>Inside Plug-ins and Fragments packaged as JARs</li>
+ <li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
+ <li>Feature directories</li>
+</ul>
+
+<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
+installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
+inform you where you can locate them. Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
+that directory.</p>
+
+<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+
+<ul>
+ <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
+ <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
+ <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
+ <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
+ <li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li>
+ <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
+</ul>
+
+<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+
+
+<h3>Use of Provisioning Technology</h3>
+
+<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
+ Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
+ other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
+ install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
+ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+ (&quot;Specification&quot;).</p>
+
+<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
+ applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
+ in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
+ Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+
+<ol>
+ <li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
+ on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
+ product.</li>
+ <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
+ accessed and copied to the Target Machine.</li>
+ <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
+ Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
+ Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
+ the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
+ indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
+</ol>
+
+<h3>Cryptography</h3>
+
+<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
+ another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
+ possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+
+<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
+</body>
+</html> \ No newline at end of file
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/pom.xml b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/pom.xml
new file mode 100644
index 0000000..f6fcb11
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi</artifactId>
+
+ <parent>
+
+ <groupId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi</groupId>
+
+ <artifactId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.aggregator</artifactId>
+
+ <version>0.9.0-SNAPSHOT</version>
+
+ <relativePath>..</relativePath>
+
+ </parent>
+
+ <packaging>eclipse-plugin</packaging>
+
+ <build>
+
+ <sourceDirectory>src</sourceDirectory>
+
+ <plugins>
+
+ <plugin>
+
+ <groupId>org.apache.felix</groupId>
+
+ <artifactId>maven-bundle-plugin</artifactId>
+
+ <extensions>true</extensions>
+
+ <version>1.4.0</version>
+
+ <configuration>
+
+ <instructions>
+
+ <Bundle-SymbolicName>${project..groupId}.${project..artifactId}</Bundle-SymbolicName>
+
+ <Bundle-Name>${project..name}</Bundle-Name>
+
+ <Bundle-Version>${project..version}</Bundle-Version>
+
+ <Export-Package>
+
+ org.eclipse.osbp.fork.mihalis.opal*,
+
+ </Export-Package>
+
+ <Bundle-Activator>org.eclipse.osbp.fork.mihalis.opal.Activator</Bundle-Activator>
+
+ </instructions>
+
+ </configuration>
+
+ </plugin>
+
+ </plugins>
+
+ </build>
+
+ <dependencies>
+
+ <dependency>
+
+ <groupId>
+
+ org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi
+
+ </groupId>
+
+ <artifactId>org.mihalis.opal</artifactId>
+
+ <version>1.0.3-SNAPSHOT</version>
+
+ </dependency>
+
+ <dependency>
+
+ <groupId>org.eclipse.osbp.gitinfo</groupId>
+
+ <artifactId>org.eclipse.osbp.gitinfo</artifactId>
+
+ <version>0.9.0-SNAPSHOT</version>
+
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/Activator.java b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/Activator.java
new file mode 100644
index 0000000..683af93
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/Activator.java
@@ -0,0 +1,56 @@
+/**
+ *
+ * Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
+ */
+
+package org.eclipse.osbp.fork.mihalis.opal;
+
+import org.eclipse.osbp.gitinfo.Loginfo;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+
+/**
+ * The Class Activator.
+ */
+public class Activator implements BundleActivator {
+
+ /** The context. */
+ private static BundleContext context;
+
+ /**
+ * Gets the context.
+ *
+ * @return the context
+ */
+ static BundleContext getContext() {
+ return context;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext bundleContext) throws Exception {
+ Activator.context = bundleContext; // NOSONAR
+ Loginfo li = new Loginfo();
+ li.print( Activator.class.getCanonicalName(), Activator.class.getClassLoader());
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext bundleContext) throws Exception {
+ Activator.context = null; // NOSONAR
+ }
+
+}
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/imageSelector/ISItem.java b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/imageSelector/ISItem.java
new file mode 100644
index 0000000..c9b892b
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/imageSelector/ISItem.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial implementation and API
+ *******************************************************************************/
+package org.eclipse.osbp.fork.mihalis.opal.imageSelector;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+
+import org.apache.commons.io.FilenameUtils;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
+import org.mihalis.opal.OpalItem;
+import org.osgi.framework.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.eclipse.osbp.fork.mihalis.opal.imageSelector.ISItem;
+
+/**
+ * Instances of this class represents items manipulated by the ImageSelector
+ * widget.
+ */
+public class ISItem extends OpalItem implements Comparable<ISItem> {
+
+ /** The z position. */
+ private double zPosition;
+
+ /** The upper left corner. */
+ private Point upperLeftCorner;
+
+ /** The lower right corner. */
+ private Point lowerRightCorner;
+
+ /** The url. */
+ private URL url;
+
+ /** The swt image. */
+ private Image swtImage;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = LoggerFactory.getLogger( ISItem.class );
+
+ /**
+ * Constructor.
+ *
+ * @param imgFile
+ * the img file
+ */
+ public ISItem(final File imgFile) {
+ try (InputStream is = imgFile.toURI().toURL().openStream()) {
+ swtImage = new Image( Display.getCurrent(), is );
+ setImage( swtImage );
+ setText(FilenameUtils.removeExtension(imgFile.getName()));
+ setUrl(imgFile.toURI().toURL());
+ } catch (IOException e) {
+ LOGGER.error(e.getLocalizedMessage());
+ }
+
+ }
+
+ /**
+ * Dispose SWT image.
+ */
+ public void dispose () {
+ swtImage.dispose();
+ }
+
+ /**
+ * Gets the url.
+ *
+ * @return the url
+ */
+ public URL getUrl() {
+ return url;
+ }
+
+ /**
+ * Sets the url.
+ *
+ * @param url
+ * the new url
+ */
+ public void setUrl(URL url) {
+ this.url = url;
+ }
+
+ /**
+ * Gets the z position.
+ *
+ * @return the zPosition
+ */
+ double getzPosition() {
+ return this.zPosition;
+ }
+
+ /**
+ * Setz position.
+ *
+ * @param zPosition
+ * the zPosition to set
+ * @return the checks if is item
+ */
+ ISItem setzPosition(final double zPosition) {
+ this.zPosition = zPosition;
+ return this;
+ }
+
+ /**
+ * Gets the upper left corner.
+ *
+ * @return the upperLeftCorner
+ */
+ Point getUpperLeftCorner() {
+ return this.upperLeftCorner;
+ }
+
+ /**
+ * Sets the upper left corner.
+ *
+ * @param x
+ * the upperLeftCorner.x to set
+ * @param y
+ * the upperLeftCorner.y to set
+ */
+ void setUpperLeftCorner(final int x, final int y) {
+ this.upperLeftCorner = new Point(x, y);
+ }
+
+ /**
+ * Gets the lower right corner.
+ *
+ * @return the lowerRightCorner
+ */
+ Point getLowerRightCorner() {
+ return this.lowerRightCorner;
+ }
+
+ /**
+ * Sets the lower right corner.
+ *
+ * @param x
+ * the lowerRightCorner.x to set
+ * @param y
+ * the lowerRightCorner.y to set
+ */
+ void setLowerRightCorner(final int x, final int y) {
+ this.lowerRightCorner = new Point(x, y);
+ }
+
+ /**
+ * Reset corner to null.
+ */
+ void resetCornerToNull() {
+ this.upperLeftCorner = null;
+ this.lowerRightCorner = null;
+
+ }
+
+ /**
+ * To string.
+ *
+ * @return the string
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "CCISItem [getText()=" + this.getText() + "]";
+ }
+
+ /**
+ * Compare to.
+ *
+ * @param o
+ * the o
+ * @return the int
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(final ISItem o) {
+ return new Double(Math.abs(this.zPosition)).compareTo(Math.abs(o
+ .getzPosition())) * -1;
+ }
+
+ /**
+ * Indicates whether some other {@code CCISItem} is "equal" to this one. Two
+ * objects of type {@code CCISItem} are considered "equal" if their
+ * attributes {@literal zPosition} are equal.
+ *
+ * If the passed object is null or <b>not</b> of type {@code CCISItem} the
+ * method returns {@code false}. Returns {@code true} if the result of
+ * method {@code compareTo()} is 0} .
+ *
+ * This method is overridden so as to maintain the general contract for
+ * classes that implement the {@code Comparable} interface.
+ *
+ * @author gu
+ * @param o
+ * the reference object with which to compare (should be of type
+ * CCISItem).
+ * @return {@code true} if this {@code CCISItem} is the same as the passed
+ * object of type {@code CCISItem}; {@code false} otherwise.
+ * @see java.lang.Object#equals(java.lang.Object)
+ * @see compareTo
+ */
+ @Override
+ public boolean equals ( Object o ) {
+ if ( o == null )
+ return false;
+
+ if ( o.getClass() != this.getClass() )
+ return false;
+
+ return compareTo( (ISItem) o ) == 0;
+ }
+
+ /**
+ * Returns a hash code value for the object, which is the result of passing
+ * attribute {@literal zPosition} to method {@code Math.ceil()}.
+ *
+ * This method is overridden so as to maintain the general contract for
+ * classes that implement the {@code Comparable} interface.
+ *
+ * @author gu
+ * @return a hash code value for this object.
+ * @see java.lang.Math.ceil(double)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode () {
+ return (int) Math.ceil( zPosition );
+ }
+
+}
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/imageSelector/ImageSelector.java b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/imageSelector/ImageSelector.java
new file mode 100644
index 0000000..c114c0b
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/imageSelector/ImageSelector.java
@@ -0,0 +1,900 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial implementation and API
+ * Romain Guy - Original Swing Implementation (http://www.curious-creature.org/2005/07/09/a-music-shelf-in-java2d/)
+ *******************************************************************************/
+package org.eclipse.osbp.fork.mihalis.opal.imageSelector;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+//import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+
+
+import java.util.Set;
+
+
+
+
+//import org.eclipse.core.internal.runtime.PlatformURLConverter;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+//import org.eclipse.emf.common.util.URI;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+import org.osgi.framework.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.eclipse.osbp.fork.mihalis.opal.imageSelector.ISItem;
+import org.eclipse.osbp.fork.mihalis.opal.imageSelector.ImageSelector;
+import org.eclipse.osbp.utils.themes.ui.VaaclipseUiTheme;
+import org.eclipse.osbp.utils.themes.ui.VaaclipseUiTheme.ThemeList;
+
+/**
+ * Instances of this class are controls that allow the user to select images.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ */
+public class ImageSelector extends Canvas {
+
+ /** The items. */
+ private List<ISItem> items;
+
+ /** The original items. */
+ private List<ISItem> originalItems;
+
+ /** The font. */
+ private Font font;
+
+ /** The max item width. */
+ private int maxItemWidth;
+
+ /** The index. */
+ private int index = -1;
+
+ /** The sigma. */
+ private double sigma;
+
+ /** The rho. */
+ private double rho;
+
+ /** The exp multiplier. */
+ private double expMultiplier;
+
+ /** The exp member. */
+ private double expMember;
+
+ /** The spacing. */
+ private float spacing = 0.4f;
+
+ /** The gradient start. */
+ private Color gradientStart;
+
+ /** The gradient end. */
+ private Color gradientEnd;
+
+ /** The animation step. */
+ private double animationStep = -1d;
+
+ /** The Constant TIMER_INTERVAL. */
+ private static final int TIMER_INTERVAL = 50;
+
+ /** The page increment. */
+ private int pageIncrement = 5;
+
+ /** The image platform path. */
+ // enhanced attributes
+ private String imagePlatformPath;
+
+ /** The image name. */
+ private String imageName;
+
+ /** The parent. */
+ private Composite parent;
+
+ /** The font name. */
+ private String FONT_NAME = "Lucida Sans";
+
+ /** The first action. */
+ // to avoid stupid actions from xtext
+ boolean firstAction = true;
+
+ /** The Constant LOGGER. */
+ private static final Logger LOGGER = LoggerFactory.getLogger( ImageSelector.class );
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent
+ * a composite control which will be the parent of the new
+ * instance (cannot be null)
+ * @param style
+ * the style of control to construct
+ * @param defaultWidth
+ * the default width
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException
+ * <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ public ImageSelector(final Composite parent, final int style, final int defaultWidth) {
+ super(parent, style | SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
+ this.parent = parent;
+ maxItemWidth = defaultWidth * 3;
+ this.font = new Font(this.getDisplay(), FONT_NAME, maxItemWidth / 3, SWT.NONE);
+
+ this.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ SWTGraphicUtil.safeDispose(ImageSelector.this.font);
+ SWTGraphicUtil.safeDispose(ImageSelector.this.gradientStart);
+ SWTGraphicUtil.safeDispose(ImageSelector.this.gradientEnd);
+ }
+
+ });
+
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(final PaintEvent e) {
+ ImageSelector.this.paintControl(e);
+ }
+
+ });
+
+ addKeyListener();
+ addMouseListeners();
+
+ setSigma(0.5);
+ this.gradientStart = new Color(getDisplay(), 0, 0, 0);
+ this.gradientEnd = new Color(getDisplay(), 110, 110, 110);
+ }
+
+ /**
+ * Set the sigma value for the gaussian curve.
+ *
+ * @param sigma
+ * new sigma parameter
+ */
+ public void setSigma(final double sigma) {
+ this.sigma = sigma;
+ this.rho = 1.0;
+ computeEquationParts();
+ this.rho = computeModifierUnbounded(0.0);
+ computeEquationParts();
+ redraw();
+ }
+
+ /**
+ * Computer both members of the equation.
+ */
+ private void computeEquationParts() {
+ this.expMultiplier = Math.sqrt(2.0 * Math.PI) / this.sigma / this.rho;
+ this.expMember = 4.0 * this.sigma * this.sigma;
+ }
+
+ /**
+ * Compute the value of the modifier. The value is bounded between -1 and +1
+ *
+ * @param x
+ * input value
+ * @return the value of the modifier between -1 and +1
+ */
+ private double computeModifierBounded(final double x) {
+ double result = computeModifierUnbounded(x);
+ if (result > 1.0) {
+ result = 1.0;
+ } else if (result < -1.0) {
+ result = -1.0;
+ }
+ return result;
+ }
+
+ /**
+ * Compute the value of the modifier.
+ *
+ * @param x
+ * input value
+ * @return the value of the function
+ */
+ private double computeModifierUnbounded(final double x) {
+ return this.expMultiplier * Math.exp(-x * x / this.expMember);
+ }
+
+ /**
+ * Draw the widget.
+ *
+ * @param e
+ * the paintEvent
+ */
+ private void paintControl(final PaintEvent e) {
+
+ // Create the image to fill the canvas
+ final Image image = new Image(getDisplay(), getClientArea());
+
+ // Set up the offscreen gc
+ final GC gc = new GC(image);
+
+ // Draw gradient
+ drawBackground(gc);
+
+ // Draw the items
+ drawItems(gc);
+
+ // Draw the title
+ if (this.animationStep < 0d) {
+ drawTitle(gc);
+ }
+
+ // Draw the offscreen buffer to the screen
+ e.gc.drawImage(image, 0, 0);
+
+ // Clean up
+ image.dispose();
+ gc.dispose();
+
+ }
+
+ /**
+ * Draw the background.
+ *
+ * @param gc
+ * graphical context
+ */
+ private void drawBackground(final GC gc) {
+ final Rectangle rect = getClientArea();
+
+ gc.setForeground(this.gradientStart);
+ gc.setBackground(this.gradientEnd);
+ gc.fillGradientRectangle(rect.x, rect.y, rect.width, rect.height / 2,
+ true);
+
+ gc.setForeground(this.gradientEnd);
+ gc.setBackground(this.gradientStart);
+ gc.fillGradientRectangle(rect.x, rect.height / 2, rect.width,
+ rect.height / 2, true);
+ }
+
+ /**
+ * Draw the items.
+ *
+ * @param gc
+ * graphical context
+ */
+ private void drawItems(final GC gc) {
+
+ if (this.animationStep < 0d) {
+ this.items.clear();
+// clearItems();
+ this.items.addAll(this.originalItems);
+ for (int i = 0; i < this.items.size(); i++) {
+ final ISItem item = this.items.get(i);
+ item.setzPosition((i - this.index) * this.spacing);
+ }
+
+ Collections.sort(this.items);
+ }
+
+ for (final ISItem item : this.items) {
+ drawItem(gc, item);
+ }
+ }
+
+ /**
+ * Draw a given item.
+ *
+ * @param gc
+ * graphical context
+ * @param item
+ * item to draw
+ */
+ private void drawItem(final GC gc, final ISItem item) {
+
+ final int size = computeSize(item);
+ final int centerX = computeZPosition(item);
+ final int centerY = this.getClientArea().height / 2;
+
+ if (size <= 0 || centerX < 0 || centerX > getBounds().width) {
+ item.resetCornerToNull();
+ return;
+ }
+
+// if ( !item.getText().equals( "grad-dark-bottom2" ) )
+// return;
+
+ final int alpha = computeAlpha(item);
+
+ final Image newImage = SWTGraphicUtil.createReflectedResizedImage( item.getImage(), size, size );
+ gc.setAlpha(alpha);
+
+ final int x = centerX - newImage.getBounds().width / 2;
+ final int y = centerY - newImage.getBounds().height / 2;
+
+ gc.drawImage(newImage, x, y);
+
+ item.setUpperLeftCorner(x, y);
+ item.setLowerRightCorner( x + newImage.getBounds().width, (int) (y + newImage.getBounds().height / 1.5) );
+
+ newImage.dispose();
+ }
+
+ /**
+ * Compute the z position for a given item.
+ *
+ * @param item
+ * item
+ * @return the z position of the item
+ */
+ private int computeZPosition(final ISItem item) {
+ final int totalWidth = this.getClientArea().width / 2;
+ final int centerX = this.getClientArea().width / 2;
+ return (int) (centerX + item.getzPosition() * totalWidth);
+ }
+
+ /**
+ * Compute size for a given item.
+ *
+ * @param item
+ * item
+ * @return the size of the item
+ */
+ private int computeSize(final ISItem item) {
+ return (int) (computeModifierBounded(item.getzPosition()) * this.maxItemWidth);
+ }
+
+ /**
+ * Compute the alpha value of a given item.
+ *
+ * @param item
+ * item
+ * @return the alpha value of the item
+ */
+ private int computeAlpha(final ISItem item) {
+ return (int) (255 - 150 * Math.abs(item.getzPosition()));
+ }
+
+ /**
+ * Draw the title under the selected item.
+ *
+ * @param gc
+ * graphical context
+ */
+ private void drawTitle(final GC gc) {
+ try {
+ final String title = this.originalItems.get(this.index).getText();
+ if (title == null || title.trim().equals("")) {
+ return;
+ }
+ gc.setFont(getFont());
+ final Point textSize = gc.stringExtent(title);
+
+ gc.setAntialias(SWT.ON);
+ gc.setFont(getFont());
+ gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ gc.setAlpha(255);
+
+ final int centerX = this.getClientArea().width / 2;
+ final int centerY = (this.getClientArea().height + this.maxItemWidth) / 2;
+
+ gc.drawString(title, centerX - textSize.x / 2,
+ (centerY - textSize.y / 2), true);
+ } catch (IndexOutOfBoundsException e) { // NOSONAR
+ // do nothing
+ }
+ }
+
+ /**
+ * Add the key listener.
+ */
+ private void addKeyListener() {
+ this.addKeyListener(new KeyAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.KeyAdapter#keyReleased(org.eclipse.swt.events.KeyEvent)
+ */
+ @Override
+ public void keyReleased(final KeyEvent e) {
+ switch (e.keyCode) {
+ case SWT.ARROW_LEFT:
+ case SWT.ARROW_UP:
+ scrollAndAnimateBy(-1);
+ break;
+ case SWT.ARROW_RIGHT:
+ case SWT.ARROW_DOWN:
+ scrollAndAnimateBy(1);
+ break;
+ case SWT.HOME:
+ scrollBy(-1 * ImageSelector.this.index);
+ break;
+ case SWT.END:
+ scrollBy(ImageSelector.this.index);
+ break;
+ case SWT.PAGE_UP:
+ scrollBy(-1 * ImageSelector.this.pageIncrement);
+ break;
+ case SWT.PAGE_DOWN:
+ scrollBy(ImageSelector.this.pageIncrement);
+ break;
+ case SWT.KEYPAD_CR:
+ case SWT.CR:
+ if (!firstAction) {
+ selectImage();
+ }
+ break;
+ }
+ firstAction = false;
+ }
+
+ });
+ }
+
+ /**
+ * Scroll the selected item.
+ *
+ * @param increment
+ * increment value
+ */
+ private void scrollBy(final int increment) {
+ this.index += increment;
+ if (this.index < 0) {
+ this.index = 0;
+ }
+
+ if (this.index >= this.items.size()) {
+ this.index = this.items.size() - 1;
+ }
+ redraw();
+ }
+
+ /**
+ * Scroll the selected item with an animation.
+ *
+ * @param increment
+ * increment value
+ */
+ private void scrollAndAnimateBy(final int increment) {
+ if (this.index == 0 && increment < 0
+ || this.index == this.items.size() - 1 && increment > 0) {
+ return;
+ }
+
+ final double step = Math.abs(increment) / (300d / TIMER_INTERVAL);
+ ImageSelector.this.animationStep = step;
+ setCursor(getDisplay().getSystemCursor(SWT.CURSOR_WAIT));
+
+ getDisplay().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+
+ ImageSelector.this.items.clear();
+// clearItems();
+ ImageSelector.this.items
+ .addAll(ImageSelector.this.originalItems);
+ for (int i = 0; i < ImageSelector.this.items.size(); i++) {
+ final ISItem item = ImageSelector.this.items.get(i);
+ item.setzPosition((i - ImageSelector.this.index + ImageSelector.this.animationStep
+ * (increment > 0 ? -1d : 1d))
+ * ImageSelector.this.spacing);
+ }
+ Collections.sort(ImageSelector.this.items);
+ if (!isDisposed()) {
+ redraw();
+ }
+
+ ImageSelector.this.animationStep += step;
+ if (ImageSelector.this.animationStep >= 1d) {
+ ImageSelector.this.animationStep = -1d;
+ ImageSelector.this.index += increment;
+ setCursor(getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
+ } else {
+ if (!isDisposed()) {
+ getDisplay().timerExec(TIMER_INTERVAL, this);
+ }
+ }
+
+ }
+ });
+
+ }
+
+ /**
+ * Add mouse listeners.
+ */
+ private void addMouseListeners() {
+ addMouseMoveListener(new MouseMoveListener() {
+ @Override
+ public void mouseMove(final MouseEvent e) {
+ for (final ISItem item : ImageSelector.this.items) {
+ if (item.getUpperLeftCorner() != null
+ && item.getLowerRightCorner() != null
+ && e.x >= item.getUpperLeftCorner().x
+ && e.x <= item.getLowerRightCorner().x
+ && e.y >= item.getUpperLeftCorner().y
+ && e.y <= item.getLowerRightCorner().y) {
+ setCursor(getDisplay().getSystemCursor(SWT.CURSOR_HAND));
+ return;
+ }
+ }
+ setCursor(getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
+ }
+ });
+
+ addMouseListener(new MouseAdapter() {
+
+ private int clicks = 0;
+
+ /**
+ * @see org.eclipse.swt.events.MouseAdapter#mouseUp(org.eclipse.swt.events.MouseEvent)
+ */
+ @Override
+ public void mouseUp(final MouseEvent e) {
+ firstAction = false;
+ Display.getDefault().timerExec(100, new Runnable() {
+
+ public void run() {
+ if (clicks > 0) {
+ clicks--;
+ return;
+ }
+ System.out.println("mouseUp");
+ for (final ISItem item : ImageSelector.this.items) {
+ if (item.getUpperLeftCorner() != null
+ && item.getLowerRightCorner() != null
+ && e.x >= item.getUpperLeftCorner().x
+ && e.x <= item.getLowerRightCorner().x
+ && e.y >= item.getUpperLeftCorner().y
+ && e.y <= item.getLowerRightCorner().y) {
+ scrollAndAnimateBy(ImageSelector.this.originalItems
+ .indexOf(item)
+ - ImageSelector.this.index);
+ return;
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public void mouseDoubleClick(final MouseEvent e) {
+ firstAction = false;
+ clicks = 2;
+ selectImage();
+ }
+
+ });
+
+ addListener(SWT.MouseWheel, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ firstAction = false;
+ scrollBy(-1 * event.count);
+ }
+ });
+
+ }
+
+ /**
+ * Gets the items.
+ *
+ * @return the items displayed by this widget
+ */
+ public List<ISItem> getItems() {
+ return this.originalItems;
+ }
+
+ /**
+ * Sets the items.
+ *
+ * @param items
+ * the items that are displayed in this widget to set
+ */
+ public void setItems(final List<ISItem> items) {
+ this.items = new ArrayList<ISItem>(items);
+ this.originalItems = items;
+ this.index = this.items.size() / 2;
+ redraw();
+ }
+
+ /**
+ * Sets the items.
+ *
+ * @param filterExtensions
+ * the new items
+ */
+ public void setItems(final String [] filterExtensions) {
+ // Create the list of images
+ final List<ISItem> items = new LinkedList<ISItem>();
+ URI iconsUri = null;
+ Set<VaaclipseUiTheme> themes = VaaclipseUiTheme.values(ThemeList.forProduct);
+ for (VaaclipseUiTheme vaaclipseUiTheme : themes) {
+ if(vaaclipseUiTheme.hasIconsUri()) {
+ iconsUri = vaaclipseUiTheme.getIconsUri();
+ break;
+ }
+ }
+ if(iconsUri == null) {
+ LOGGER.error("no theme provider bundle found");
+ return;
+ }
+ try {
+ File pathFolder = new File(FileLocator.toFileURL(iconsUri.toURL()).getPath());
+ if (pathFolder.isDirectory()) {
+ File[] imgFiles = pathFolder.listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String filename) {
+ for (int i = 0; i < filterExtensions.length; i++) {
+ boolean fileNameFound = filename.endsWith(filterExtensions[i]);
+ if (fileNameFound) return fileNameFound;
+ }
+ return false;
+ }
+ });
+ if ( imgFiles != null ) {
+ for (File imgFile : imgFiles) {
+ items.add( new ISItem(imgFile));
+ }
+ }
+ }
+ setItems(items);
+ } catch (IOException e) {
+ LOGGER.error(e.getLocalizedMessage()+e.getCause().getLocalizedMessage());
+ }
+ }
+
+ /**
+ * Disposes all SWT-items within CCISItem-list {@literal}items. Clears list
+ * afterwards.
+ *
+ * @return void
+ */
+ public void clearItems () {
+ for ( ISItem item : this.items ) {
+ item.dispose();
+ }
+ this.items.clear();
+ }
+
+ /**
+ * Gets the font.
+ *
+ * @return the font used for the title
+ */
+ @Override
+ public Font getFont() {
+ return this.font;
+ }
+
+ /**
+ * Sets the font.
+ *
+ * @param font
+ * the font used for the title to set
+ */
+ @Override
+ public void setFont(final Font font) {
+ SWTGraphicUtil.safeDispose(this.font);
+ this.font = font;
+ redraw();
+ }
+
+ /**
+ * Gets the index.
+ *
+ * @return the index of the selected image
+ */
+ public int getIndex() {
+ return this.index;
+ }
+
+ /**
+ * Sets the index.
+ *
+ * @param index
+ * the index of the selected image to set
+ */
+ public void setIndex(final int index) {
+ this.index = index;
+ redraw();
+ }
+
+ /**
+ * Gets the max item width.
+ *
+ * @return the maximum items width
+ */
+ public int getMaxItemWidth() {
+ return this.maxItemWidth;
+ }
+
+ /**
+ * Sets the max item width.
+ *
+ * @param maxItemWidth
+ * the the maximum items width to set
+ */
+ public void setMaxItemWidth(final int maxItemWidth) {
+ this.maxItemWidth = maxItemWidth;
+ redraw();
+ }
+
+ /**
+ * Gets the sigma.
+ *
+ * @return the sigma value
+ */
+ public double getSigma() {
+ return this.sigma;
+ }
+
+ /**
+ * Gets the spacing.
+ *
+ * @return the spacing between 2 items
+ */
+ public float getSpacing() {
+ return this.spacing;
+ }
+
+ /**
+ * Sets the spacing.
+ *
+ * @param spacing
+ * the the spacing between 2 items to set
+ */
+ public void setSpacing(final float spacing) {
+ this.spacing = spacing;
+ redraw();
+ }
+
+ /**
+ * Gets the gradient start.
+ *
+ * @return the gradient start color
+ */
+ public Color getGradientStart() {
+ return this.gradientStart;
+ }
+
+ /**
+ * Sets the gradient start.
+ *
+ * @param gradientStart
+ * the the gradient start color to set
+ */
+ public void setGradientStart(final Color gradientStart) {
+ SWTGraphicUtil.safeDispose(this.gradientStart);
+ this.gradientStart = gradientStart;
+ redraw();
+ }
+
+ /**
+ * Gets the gradient end.
+ *
+ * @return the the gradient end color
+ */
+ public Color getGradientEnd() {
+ return this.gradientEnd;
+ }
+
+ /**
+ * Sets the gradient end.
+ *
+ * @param gradientEnd
+ * the the gradient end color to set
+ */
+ public void setGradientEnd(final Color gradientEnd) {
+ SWTGraphicUtil.safeDispose(this.gradientEnd);
+ this.gradientEnd = gradientEnd;
+ redraw();
+ }
+
+ /**
+ * Gets the page increment.
+ *
+ * @return the page increment when the user uses PgUp and PgDown
+ */
+ public int getPageIncrement() {
+ return this.pageIncrement;
+ }
+
+ /**
+ * Sets the page increment.
+ *
+ * @param pageIncrement
+ * the page increment to set
+ */
+ public void setPageIncrement(final int pageIncrement) {
+ this.pageIncrement = pageIncrement;
+ }
+
+ /**
+ * Select image.
+ */
+ private void selectImage() {
+ int idx = ImageSelector.this.index;
+
+ try {
+ ISItem isItem = ImageSelector.this.originalItems.get(idx);
+ imagePlatformPath = isItem.getUrl().toString();
+ imageName = isItem.getText();
+ this.parent.dispose();
+ } catch (IndexOutOfBoundsException e) {
+ // do nothing
+ e.printStackTrace(); // NOSONAR
+ LOGGER.warn( String.format( "selectImage(): no index %d in originalItems", idx ), e );
+ }
+ }
+
+ /**
+ * Gets the image platform path.
+ *
+ * @return the image platform path
+ */
+ public String getImagePlatformPath() {
+ return imagePlatformPath;
+ }
+
+ /**
+ * Gets the image name.
+ *
+ * @return the image name
+ */
+ public String getImageName() {
+ return imageName;
+ }
+
+}
diff --git a/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/widgets/ImageSelectorDialog.java b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/widgets/ImageSelectorDialog.java
new file mode 100644
index 0000000..8cfa6a7
--- /dev/null
+++ b/org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi/src/org/eclipse/osbp/fork/mihalis/opal/widgets/ImageSelectorDialog.java
@@ -0,0 +1,196 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osbp.fork.mihalis.opal.widgets;
+
+import org.eclipse.osbp.fork.mihalis.opal.imageSelector.ImageSelector;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.widgets.Dialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Instances of this class allow the user to navigate the file system and select
+ * or enter a file name.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>SAVE, OPEN, MULTI</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles SAVE and OPEN may be specified.
+ * </p>
+ * <p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#filedialog">FileDialog
+ * snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example:
+ * ControlExample, Dialog tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further
+ * information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ImageSelectorDialog extends Dialog {
+
+ /** The image width. */
+ int imageWidth;
+
+ /** The filter extensions. */
+ String[] filterExtensions = new String[0];
+
+ /**
+ * Constructs a new instance of this class given only its parent.
+ *
+ * @param parent
+ * a shell which will be the parent of the new instance
+ * @param imageWidth
+ * the image width
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException
+ * <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an
+ * allowed subclass</li>
+ * </ul>
+ */
+ public ImageSelectorDialog(Shell parent, int imageWidth) {
+ this(parent, SWT.APPLICATION_MODAL, imageWidth);
+ }
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent
+ * a shell which will be the parent of the new instance
+ * @param style
+ * the style of dialog to construct
+ * @param imageWidth
+ * the image width
+ * @see SWT#SAVE
+ * @see SWT#OPEN
+ * @see SWT#MULTI
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException
+ * <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an
+ * allowed subclass</li>
+ * </ul>
+ */
+ public ImageSelectorDialog(Shell parent, int style, int imageWidth) {
+ super(parent, style);
+ this.imageWidth = imageWidth;
+ }
+
+ /**
+ * Returns the file extensions which the dialog will use to filter the files
+ * it shows.
+ *
+ * @return the file extensions filter
+ */
+ public String[] getFilterExtensions() {
+ return filterExtensions;
+ }
+
+ /**
+ * Makes the dialog visible and brings it to the front of the display.
+ *
+ * @return a string describing the absolute path of the first selected file,
+ * or null if the dialog was cancelled or an error occurred
+ *
+ * @exception SWTException
+ * <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the dialog has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the dialog</li>
+ * </ul>
+ */
+ public String open() {
+ return open(false);
+ }
+
+ /**
+ * Open.
+ *
+ * @param returnSimpleName
+ * the return simple name
+ * @return the string
+ */
+ public String open(boolean returnSimpleName) {
+ /* Make the parent shell be temporary modal */
+ Display display = getParent().getDisplay();
+
+ /*
+ * Open the dialog.
+ */
+ final ImageSelector imageSelector = new ImageSelector(getParent(),
+ getStyle(), imageWidth);
+ imageSelector.setItems(filterExtensions);
+
+ // Open the shell
+ getParent().setSize(6*3*imageWidth, 3*3*imageWidth);
+ getParent().open();
+ while (!getParent().isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ imageSelector.clearItems();
+
+ if (returnSimpleName) {
+ return imageSelector.getImageName();
+ } else {
+ return imageSelector.getImagePlatformPath();
+ }
+ }
+
+ /**
+ * Set the file extensions which the dialog will use to filter the files it
+ * shows to the argument, which may be null.
+ * <p>
+ * The strings are platform specific. For example, on some platforms, an
+ * extension filter string is typically of the form "*.extension", where
+ * "*.*" matches all files. For filters with multiple extensions, use
+ * semicolon as a separator, e.g. "*.jpg;*.png".
+ * </p>
+ *
+ * @param extensions
+ * the file extension filter
+ *
+ * @see #setFilterNames to specify the user-friendly names corresponding to
+ * the extensions
+ */
+ public void setFilterExtensions(String[] extensions) {
+ filterExtensions = extensions;
+ }
+}
diff --git a/org.mihalis.opal/.classpath b/org.mihalis.opal/.classpath
new file mode 100644
index 0000000..bfe58f5
--- /dev/null
+++ b/org.mihalis.opal/.classpath
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src/main/java/"/>
+ <classpathentry kind="src" path="src/main/resources/"/>
+ <classpathentry kind="src" path="src/test/java/"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/org.mihalis.opal/.gitignore b/org.mihalis.opal/.gitignore
new file mode 100644
index 0000000..99d2bb1
--- /dev/null
+++ b/org.mihalis.opal/.gitignore
@@ -0,0 +1,2 @@
+/target/
+/build/
diff --git a/org.mihalis.opal/.project b/org.mihalis.opal/.project
new file mode 100644
index 0000000..bdc6df0
--- /dev/null
+++ b/org.mihalis.opal/.project
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.mihalis.opal</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.babel.editor.rbeBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.sonarlint.eclipse.core.sonarlintBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.babel.editor.rbeNature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.mihalis.opal/.settings/org.eclipse.core.resources.prefs b/org.mihalis.opal/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..340b568
--- /dev/null
+++ b/org.mihalis.opal/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/main/resources/resources/opal_pl_PL.properties=UTF-8
+encoding//src/test/java=UTF-8
+encoding/<project>=UTF-8
+encoding/src=UTF-8
diff --git a/org.mihalis.opal/.settings/org.eclipse.jdt.core.prefs b/org.mihalis.opal/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..e8b43cd
--- /dev/null
+++ b/org.mihalis.opal/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,297 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=250
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/org.mihalis.opal/.settings/org.eclipse.jdt.ui.prefs b/org.mihalis.opal/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..2591b05
--- /dev/null
+++ b/org.mihalis.opal/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,62 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=true
+cleanup.format_source_code=true
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=true
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_Opal
+cleanup_settings_version=2
+eclipse.preferences.version=1
+formatter_profile=_Opal
+formatter_settings_version=12
diff --git a/org.mihalis.opal/.settings/org.eclipse.m2e.core.prefs b/org.mihalis.opal/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..5ad21a1
--- /dev/null
+++ b/org.mihalis.opal/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,5 @@
+#Wed Oct 26 10:50:16 CEST 2011
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/org.mihalis.opal/.settings/org.eclipse.xtend.core.Xtend.prefs b/org.mihalis.opal/.settings/org.eclipse.xtend.core.Xtend.prefs
new file mode 100644
index 0000000..cf5bcee
--- /dev/null
+++ b/org.mihalis.opal/.settings/org.eclipse.xtend.core.Xtend.prefs
@@ -0,0 +1,11 @@
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/main/java.directory=xtend-gen
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/test/java.directory=src/test/generated-sources/xtend
+eclipse.preferences.version=1
+is_project_specific=true
+outlet.DEFAULT_OUTPUT.hideLocalSyntheticVariables=true
+outlet.DEFAULT_OUTPUT.installDslAsPrimarySource=false
+outlet.DEFAULT_OUTPUT.sourceFolder.emf-gen.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.sourceFolder.src-gen.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.sourceFolder.src.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.sourceFolder.xtend-gen.directory=xtend-gen
+outlet.DEFAULT_OUTPUT.userOutputPerSourceFolder=true
diff --git a/org.mihalis.opal/LICENSE.txt b/org.mihalis.opal/LICENSE.txt
new file mode 100644
index 0000000..ff42ad4
--- /dev/null
+++ b/org.mihalis.opal/LICENSE.txt
@@ -0,0 +1,161 @@
+Eclipse Public License -v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION
+OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
+
+b) in the case of each subsequent Contributor:
+
+i) changes to the Program, and
+
+ii) additions to the Program;
+
+where such changes and/or additions to the Program originate from and are distributed by that particular Contributor.
+A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone
+acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate
+modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not
+derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of
+its Contribution alone or when combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute
+and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code
+form.
+
+b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the
+Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the
+combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such
+addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not
+apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
+
+c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no
+assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property
+rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity
+based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and
+licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property
+rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the
+Program, it is Recipient's responsibility to acquire that license before distributing the Program.
+
+d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to
+grant the copyright license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
+
+a) it complies with the terms and conditions of this Agreement; and
+
+b) its license agreement:
+
+i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including
+warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and
+fitness for a particular purpose;
+
+ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special,
+incidental and consequential damages, such as lost profits;
+
+iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any
+other party; and
+
+iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it
+in a reasonable manner on or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+a) it must be made available under this Agreement; and
+
+b) a copy of this Agreement must be included with each copy of the Program.
+
+Contributors may not remove or alter any copyright notices contained within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and
+the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes
+the Program in a commercial product offering should do so in a manner which does not create potential liability for
+other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor")
+against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions
+brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual
+property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the
+Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may
+ participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is
+then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties
+related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone.
+Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to
+those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result,
+the Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for
+determining the appropriateness of using and distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance
+with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or
+enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such
+provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit)
+alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such
+Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or
+conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such
+noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution
+of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses
+ granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement
+is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish
+new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the
+right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may
+assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the
+Agreement will be given a distinguishing version number. The Program (including Contributions) may always be
+distributed subject to the version of the Agreement under which it was received. In addition, after a new version of
+the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the
+new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
+the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or
+otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States
+of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause
+of action arose. Each party waives its rights to a jury trial in any resulting litigation. \ No newline at end of file
diff --git a/org.mihalis.opal/META-INF/MANIFEST.MF b/org.mihalis.opal/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..2a062fc
--- /dev/null
+++ b/org.mihalis.opal/META-INF/MANIFEST.MF
@@ -0,0 +1,54 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: org.mihalis.opal
+Bundle-SymbolicName: org.mihalis.opal
+Bundle-Vendor: Eclipse OSBP
+Bundle-Version: 1.0.3.qualifier
+Export-Package: org.mihalis.opal,
+ org.mihalis.opal.angles,
+ org.mihalis.opal.breadcrumb,
+ org.mihalis.opal.brushedMetalComposite,
+ org.mihalis.opal.calculator,
+ org.mihalis.opal.checkBoxGroup,
+ org.mihalis.opal.columns,
+ org.mihalis.opal.dynamictablecolumns,
+ org.mihalis.opal.flatButton,
+ org.mihalis.opal.gradientComposite,
+ org.mihalis.opal.header,
+ org.mihalis.opal.heapManager,
+ org.mihalis.opal.horizontalSpinner,
+ org.mihalis.opal.imageSelector,
+ org.mihalis.opal.imageSelector.images,
+ org.mihalis.opal.infinitePanel,
+ org.mihalis.opal.itemSelector,
+ org.mihalis.opal.itemSelector.flags,
+ org.mihalis.opal.launcher,
+ org.mihalis.opal.launcher.icons,
+ org.mihalis.opal.login,
+ org.mihalis.opal.multiChoice,
+ org.mihalis.opal.notify,
+ org.mihalis.opal.obutton,
+ org.mihalis.opal.opalDialog,
+ org.mihalis.opal.panels,
+ org.mihalis.opal.preferenceWindow,
+ org.mihalis.opal.preferenceWindow.enabler,
+ org.mihalis.opal.preferenceWindow.images,
+ org.mihalis.opal.preferenceWindow.widgets,
+ org.mihalis.opal.promptSupport,
+ org.mihalis.opal.propertyTable,
+ org.mihalis.opal.propertyTable.editor,
+ org.mihalis.opal.rangeSlider,
+ org.mihalis.opal.roundedToolbar,
+ org.mihalis.opal.roundedToolbar.icons,
+ org.mihalis.opal.starRating,
+ org.mihalis.opal.switchButton,
+ org.mihalis.opal.systemMonitor,
+ org.mihalis.opal.textAssist,
+ org.mihalis.opal.tipOfTheDay,
+ org.mihalis.opal.titledSeparator,
+ org.mihalis.opal.transitionComposite,
+ org.mihalis.opal.utils
+Require-Bundle: org.eclipse.swt;bundle-version="3.7.2",
+ org.eclipse.osbp.gitinfo;bundle-version="[0.9.0,0.10.0)"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: org.osgi.framework
diff --git a/org.mihalis.opal/README.md b/org.mihalis.opal/README.md
new file mode 100644
index 0000000..533d1d1
--- /dev/null
+++ b/org.mihalis.opal/README.md
@@ -0,0 +1,75 @@
+# opal
+Main repository for the Opal Project (SWT new widgets library)
+
+The goal of this project is to propose new widgets for the SWT API.
+Some widgets are new, some others are a port of existing widgets made with Swing.
+
+# V1.0.3 is out
+Version 1.0.3 is ready. It contains a bug fix. You can download
+* the jar library at [https://github.com/lcaron/opal/blob/releases/V1.0.3/opal-1.0.3.jar?raw=true](https://github.com/lcaron/opal/blob/releases/V1.0.3/opal-1.0.3.jar?raw=true)
+* the source code at [https://github.com/lcaron/opal/blob/releases/V1.0.3/opal-1.0.3-src.zip?raw=true](https://github.com/lcaron/opal/blob/releases/V1.0.3/opal-1.0.3-src.zip?raw=true)
+* the OSGI bundle at [https://github.com/lcaron/opal/blob/releases/V1.0.3/opal-1.0.3-plugin.jar?raw=true](https://github.com/lcaron/opal/blob/releases/V1.0.3/opal-1.0.3-plugin.jar?raw=true)
+
+# V1.0.2 is out
+Version 1.0.2 is ready. It contains bug fixes and few enhancements. You can download
+* the jar library at [https://github.com/lcaron/opal/blob/releases/V1.0.2/opal-1.0.2.jar?raw=true](https://github.com/lcaron/opal/blob/releases/V1.0.2/opal-1.0.2.jar?raw=true)
+* the source code at [https://github.com/lcaron/opal/blob/releases/V1.0.2/opal-1.0.2-src.zip?raw=true](https://github.com/lcaron/opal/blob/releases/V1.0.2/opal-1.0.2-src.zip?raw=true)
+* the OSGI bundle at [https://github.com/lcaron/opal/blob/releases/V1.0.2/opal-1.0.2-plugin.jar?raw=true](https://github.com/lcaron/opal/blob/releases/V1.0.2/opal-1.0.2-plugin.jar?raw=true)
+
+# Forum
+Our forum is located at [https://groups.google.com/forum/#!forum/opal-project](https://groups.google.com/forum/#!forum/opal-project)
+
+# Important notice
+The SWT library in the project is the Windows 64-bit version. Please replace the swt.jar file by the appropriate one !
+
+# The widgets
+
+Currently Opal contains the following widgets :
+* __Multichoice__, a tool to select items.
+* __TextAssist__, an improved Text widget with auto-completion
+* __AngleSlider__, a angle picker
+* __Brushed Metal Composite__, a composite that displays a brushed metal texture "à la mac"
+* __Dual List__, a widget allows the user to select one or many elements, and order them.
+* __Infinite progress panel__, a widget that displays an animation during long task operations
+* __Switch button__, another look for checkboxes
+* __Gradient composite__, a composite that displays a gradient in its background.
+* __Image Selector__, a fancy image selector,
+* __Dialog box__, a trivial Task Dialog API for SWT
+* __Horizontal Spinner__, a horizontal spinner
+* __Panels__, 2 panels to make your forms nicer
+* __CheckBoxGroup__, a group with a checkbox. When one clicks on the checkbox, the whole content of the group is deactivated.
+* __HeapManager__, a widget that displays the available heap size, the current heap size and a button to perform a Garbage Collecting.
+* __ColumnBrowser__, a widget that displays a tree structure "a la mac" in miller columns.
+* __Launcher__, a widget used to launch applications, modules or anything, with a simple and fancy zoom effect
+* __Header__,a widget that displays a header, composed of a title, an image and a description.
+* __Titled Separator__, an enhanced separator, with a title and/or an image.
+* __LoginDialog__, a component to authentify users.
+* __Tip of the Day__, a window that displays the tip of the day.
+* __Preference Window__, an easy-to-build window that can be used to set up preferences.
+* __Range Slider__, a slider that allow the user to select a range
+* __Prompt Support__, an utility class to add a Prompt to Text and Combo widgets !
+* __Transition Composite__, a widget that display controls like "pages" and manage transitions between each page.
+* __Property Table__, a widget to edit properties. Each property is given a name, a type, a description.
+* __DynamicTableColumns__ an enhanced table that allow you to set width by using pixels or percentages.
+* __Notifier__ a toaster to notify the user
+* __SystemMonitor__ a widget to monitor some aspects of your system and application.
+* __Calculator__ a widget that displays a Calculator or a Calculator Combo.
+* __RoundedToolbar__ a widget that displays a rounded toolbar.
+* __StarRating__ a widget that displays a star rating component.
+* __Breadcrumb__ a widget that displays a bread crumb.
+* __OButton__ a widget that displays a custom button (Push,Toggle or Arrow).
+
+
+# Download
+All previous releases are hosted on Google Drive : https://drive.google.com/folderview?id=0BxckedW58_H5WTdQV05samZVRUE&usp=sharing
+
+
+# Support the project on Facebook
+
+http://www.facebook.com/eclipse.org/posts/273985562641654
+
+Thanks to the eclipse.org team for the link to Opal :)
+
+# We need you !
+
+Do you have coded extra widgets ? You have tested Opal on Linux and MacOS ? You speak German, Spanish, Italian, Polish, Chinese, Portuguese ? Please help us and make Opal better ! Contact us with Google Groups !
diff --git a/org.mihalis.opal/build.properties b/org.mihalis.opal/build.properties
new file mode 100644
index 0000000..a1a6e32
--- /dev/null
+++ b/org.mihalis.opal/build.properties
@@ -0,0 +1,9 @@
+source.. = src/main/java/,\
+ src/main/resources/,\
+ src/test/java/
+bin.includes = META-INF/,\
+ .,\
+ LICENSE.txt,\
+ license.html
+src.includes = LICENSE.txt,\
+ license.html
diff --git a/org.mihalis.opal/lib/swt.jar b/org.mihalis.opal/lib/swt.jar
new file mode 100644
index 0000000..1312014
--- /dev/null
+++ b/org.mihalis.opal/lib/swt.jar
Binary files differ
diff --git a/org.mihalis.opal/license.html b/org.mihalis.opal/license.html
new file mode 100644
index 0000000..c33d45c
--- /dev/null
+++ b/org.mihalis.opal/license.html
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Foundation Software User Agreement</title>
+</head>
+
+<body lang="EN-US">
+<h2>Eclipse Foundation Software User Agreement</h2>
+<p>February 1, 2011</p>
+
+<h3>Usage Of Content</h3>
+
+<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+ (COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+ CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+ OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+ NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+ CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+
+<h3>Applicable Licenses</h3>
+
+<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
+ (&quot;EPL&quot;). A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+ For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
+ repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
+
+<ul>
+ <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
+ <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
+ <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;. Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
+ and/or Fragments associated with that Feature.</li>
+ <li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
+</ul>
+
+<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
+Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and Feature Licenses may be located in any directory of a Download or Module
+including, but not limited to the following locations:</p>
+
+<ul>
+ <li>The top-level (root) directory</li>
+ <li>Plug-in and Fragment directories</li>
+ <li>Inside Plug-ins and Fragments packaged as JARs</li>
+ <li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
+ <li>Feature directories</li>
+</ul>
+
+<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
+installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
+inform you where you can locate them. Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
+that directory.</p>
+
+<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+
+<ul>
+ <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
+ <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
+ <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
+ <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
+ <li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li>
+ <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
+</ul>
+
+<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+
+
+<h3>Use of Provisioning Technology</h3>
+
+<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
+ Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
+ other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
+ install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
+ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+ (&quot;Specification&quot;).</p>
+
+<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
+ applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
+ in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
+ Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+
+<ol>
+ <li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
+ on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
+ product.</li>
+ <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
+ accessed and copied to the Target Machine.</li>
+ <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
+ Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
+ Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
+ the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
+ indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
+</ol>
+
+<h3>Cryptography</h3>
+
+<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
+ another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
+ possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+
+<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
+</body>
+</html> \ No newline at end of file
diff --git a/org.mihalis.opal/pom.xml b/org.mihalis.opal/pom.xml
new file mode 100644
index 0000000..45f1372
--- /dev/null
+++ b/org.mihalis.opal/pom.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi</groupId>
+ <artifactId>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.aggregator</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>org.mihalis.opal</artifactId>
+ <version>1.0.3-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+ <repositories>
+ <!--<repository>
+ <id>eclipse.org</id>
+ <url>http://maven.eclipse.org/nexus/content/repositories/testing/</url>
+ </repository>-->
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.swt</groupId>
+ <artifactId>org.eclipse.swt.win32.win32.x86_64</artifactId>
+ <version>[3.6,4.5.0)</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <sourceDirectory>src/main/java</sourceDirectory>
+ <testSourceDirectory>src/test/java</testSourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <version>1.4.0</version>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project..artifactId}</Bundle-SymbolicName>
+ <Bundle-Name>${project..name}</Bundle-Name>
+ <Bundle-Version>${project..version}</Bundle-Version>
+ <Export-Package>
+ org.mihalis.opal*
+ </Export-Package>
+ <Bundle-Activator>org.mihalis.opal.Activator</Bundle-Activator>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <url>https://github.com/lcaron/opal</url>
+</project>
diff --git a/org.mihalis.opal/src/images/arrowGreenRight.png b/org.mihalis.opal/src/images/arrowGreenRight.png
new file mode 100644
index 0000000..63b675c
--- /dev/null
+++ b/org.mihalis.opal/src/images/arrowGreenRight.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/Activator.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/Activator.java
new file mode 100644
index 0000000..70f09ec
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/Activator.java
@@ -0,0 +1,57 @@
+/**
+ *
+ * Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
+ */
+
+package org.mihalis.opal;
+
+import org.eclipse.osbp.gitinfo.Loginfo;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+
+
+/**
+ * The Class Activator.
+ */
+public class Activator implements BundleActivator {
+
+ /** The context. */
+ private static BundleContext context;
+
+ /**
+ * Gets the context.
+ *
+ * @return the context
+ */
+ static BundleContext getContext() {
+ return context;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext bundleContext) throws Exception {
+ Activator.context = bundleContext; // NOSONAR
+ Loginfo li = new Loginfo();
+ li.print( Activator.class.getCanonicalName(), Activator.class.getClassLoader());
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext bundleContext) throws Exception {
+ Activator.context = null; // NOSONAR
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/OpalItem.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/OpalItem.java
new file mode 100644
index 0000000..fda8be0
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/OpalItem.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Instances of this object are items manipulated by the widgets of the Opal Project. These items are highly customizable, you can set :
+ * <ul>
+ * <li>Background and foreground colors,
+ * <li>Font
+ * <li>Image
+ * <li>Text
+ * <li>Height
+ * </ul>
+ * You can also store data using the <code>setData<code> methods.
+ *
+ */
+public abstract class OpalItem {
+
+ /** The data. */
+ private final Map<String, Object> data = new HashMap<String, Object>();
+
+ /** The datum. */
+ private Object datum;
+
+ /** The background. */
+ private Color background;
+
+ /** The font. */
+ private Font font;
+
+ /** The foreground. */
+ private Color foreground;
+
+ /** The image. */
+ private Image image;
+
+ /** The text. */
+ private String text;
+
+ /** The height. */
+ private int height = -1;
+
+ /**
+ * Gets the background.
+ *
+ * @return the background color of the item
+ */
+ public Color getBackground() {
+ return this.background;
+ }
+
+ /**
+ * Gets the data.
+ *
+ * @return the the data stored in this item
+ */
+ public Object getData() {
+ return this.datum;
+ }
+
+ /**
+ * Gets the data.
+ *
+ * @param key a key
+ * @return the the data stored in this item associated to this key
+ */
+ public Object getData(final String key) {
+ return this.data.get(key);
+ }
+
+ /**
+ * Gets the font.
+ *
+ * @return the font of the item
+ */
+ public Font getFont() {
+ return this.font;
+ }
+
+ /**
+ * Gets the foreground.
+ *
+ * @return the foreground color of the item
+ */
+ public Color getForeground() {
+ return this.foreground;
+ }
+
+ /**
+ * Gets the height.
+ *
+ * @return the height of the item
+ */
+ public int getHeight() {
+ return this.height;
+ }
+
+ /**
+ * Gets the image.
+ *
+ * @return the image stored in this item
+ */
+ public Image getImage() {
+ return this.image;
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @return the text stored in this item
+ */
+ public String getText() {
+ return this.text;
+ }
+
+ /**
+ * Sets the background.
+ *
+ * @param background set the background color of this item
+ */
+ public void setBackground(final Color background) {
+ this.background = background;
+ }
+
+ /**
+ * Sets the font.
+ *
+ * @param font set the font of this item
+ */
+ public void setFont(final Font font) {
+ this.font = font;
+ }
+
+ /**
+ * Sets the foreground.
+ *
+ * @param foreground set the foreground color of this item
+ */
+ public void setForeground(final Color foreground) {
+ this.foreground = foreground;
+ }
+
+ /**
+ * Sets the height.
+ *
+ * @param height set the height of this item
+ */
+ public void setHeight(final int height) {
+ this.height = height;
+ }
+
+ /**
+ * Sets the image.
+ *
+ * @param image set the image of this item
+ */
+ public void setImage(final Image image) {
+ this.image = image;
+ }
+
+ /**
+ * Sets the text.
+ *
+ * @param text set the text of this item
+ */
+ public void setText(final String text) {
+ this.text = text;
+ }
+
+ /**
+ * Sets the data.
+ *
+ * @param data set the data stored in this item
+ */
+ public void setData(final Object data) {
+ this.datum = data;
+ }
+
+ /**
+ * Store a data associated to a given key in this item.
+ *
+ * @param key key
+ * @param value value associated to this key
+ */
+ public void setData(final String key, final Object value) {
+ this.data.put(key, value);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/angles/AngleSlider.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/angles/AngleSlider.java
new file mode 100644
index 0000000..7b16f6b
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/angles/AngleSlider.java
@@ -0,0 +1,326 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron@gmail.com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.angles;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class provide a selectable user interface object that can
+ * be used to pick angles. Inspired by the Swing AngleSlider by Jeremy
+ * (http://javagraphics.blogspot.com/2008/05/angles-need-gui-widget-for-angles.
+ * html)
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ */
+public class AngleSlider extends Canvas {
+
+ /** The Constant WHOLE_RADIUS. */
+ private static final int WHOLE_RADIUS = 40;
+
+ /** The Constant BUTTON_RADIUS. */
+ private static final int BUTTON_RADIUS = 10;
+
+ /** The Constant STEP. */
+ private static final int STEP = 5;
+
+ /** The background image. */
+ private final Image backgroundImage;
+
+ /** The button focus. */
+ private final Image buttonFocus;
+
+ /** The button no focus. */
+ private final Image buttonNoFocus;
+
+ /** The selection. */
+ private int selection;
+
+ /** The selection listeners. */
+ private final List<SelectionListener> selectionListeners;
+
+ /** The mouse pressed. */
+ private boolean mousePressed;
+
+ /**
+ * Constructs a new instance of this class given its parent.
+ *
+ * @param parent a widget which will be the parent of the new instance
+ * (cannot be null)
+ * @param style not used
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException
+ * <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ public AngleSlider(final Composite parent, final int style) {
+ super(parent, style | SWT.DOUBLE_BUFFERED);
+
+ final ClassLoader loader = org.mihalis.opal.angles.AngleSlider.class.getClassLoader();
+
+ backgroundImage = new Image(getDisplay(), loader.getResourceAsStream("images/angleBackground.png"));
+ buttonFocus = new Image(getDisplay(), loader.getResourceAsStream("images/angleButtonFocus.png"));
+ buttonNoFocus = new Image(getDisplay(), loader.getResourceAsStream("images/angleButtonFocusLost.png"));
+
+ addListeners();
+
+ selection = 0;
+ selectionListeners = new ArrayList<SelectionListener>();
+ }
+
+ /**
+ * Add listeners.
+ */
+ private void addListeners() {
+ addListener(SWT.Paint, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ paintControl(event);
+ }
+ });
+
+ addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent arg0) {
+ SWTGraphicUtil.safeDispose(backgroundImage);
+ SWTGraphicUtil.safeDispose(buttonFocus);
+ SWTGraphicUtil.safeDispose(buttonNoFocus);
+ }
+ });
+
+ final int[] listeners = new int[] { SWT.MouseDown, SWT.MouseUp, SWT.MouseMove };
+
+ for (final int listener : listeners) {
+ addListener(listener, createMouseListener());
+ }
+ addListener(SWT.KeyDown, createKeyListener());
+
+ }
+
+ /**
+ * Paint control.
+ *
+ * @param event the event
+ */
+ private void paintControl(final Event event) {
+ final GC gc = event.gc;
+
+ gc.drawImage(backgroundImage, 0, 0);
+
+ float angle = selection / 360f;
+ angle = (float) (angle * 2 * Math.PI - 0.5 * Math.PI);
+
+ final float centerX = WHOLE_RADIUS / 2f;
+ final float centerY = WHOLE_RADIUS / 2f;
+ final float radius = BUTTON_RADIUS;
+ final float x = (float) (centerX - radius * Math.cos(angle));
+ final float y = (float) (centerY - radius * Math.sin(angle));
+
+ if (isFocusControl()) {
+ gc.drawImage(buttonFocus, (int) x - 2, (int) y - 2);
+ } else {
+ gc.drawImage(buttonNoFocus, (int) x - 2, (int) y - 2);
+ }
+
+ if (!isEnabled()) {
+ gc.setAlpha(127);
+ gc.setAntialias(SWT.ON);
+ gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ gc.fillOval(4, 4, WHOLE_RADIUS - 7, WHOLE_RADIUS - 7);
+ }
+ }
+
+ /**
+ * Creates the mouse listener.
+ *
+ * @return the listener
+ */
+ private Listener createMouseListener() {
+ return new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ if (!isEnabled()) {
+ return;
+ }
+
+ if (event.type == SWT.MouseDown) {
+ mousePressed = true;
+ }
+ if (event.type == SWT.MouseDown || event.type == SWT.MouseMove && mousePressed) {
+ final float deltaX = event.x - WHOLE_RADIUS / 2f;
+ final float deltaY = event.y - WHOLE_RADIUS / 2f;
+ final double angle = Math.atan2(deltaX, deltaY);
+ selection = 360 - (int) (360 * angle / (2 * Math.PI) + 360) % 360;
+
+ redraw();
+ }
+ if (event.type == SWT.MouseUp) {
+ mousePressed = false;
+ fireSelectionListeners(event);
+ }
+ }
+ };
+ }
+
+ /**
+ * Fire selection listeners.
+ *
+ * @param event the event
+ */
+ private void fireSelectionListeners(final Event event) {
+ for (final SelectionListener selectionListener : selectionListeners) {
+ selectionListener.widgetSelected(new SelectionEvent(event));
+ }
+ }
+
+ /**
+ * Creates the key listener.
+ *
+ * @return the listener
+ */
+ private Listener createKeyListener() {
+ return new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ if (!isEnabled()) {
+ return;
+ }
+ if (event.type != SWT.KeyDown) {
+ return;
+ }
+ if (event.keyCode == SWT.ARROW_UP || event.keyCode == SWT.ARROW_LEFT) {
+ setSelection(selection + STEP);
+ }
+ if (event.keyCode == SWT.ARROW_DOWN || event.keyCode == SWT.ARROW_RIGHT) {
+ setSelection(selection - STEP);
+ }
+ }
+ };
+ }
+
+ /**
+ * Adds the selection listener.
+ *
+ * @param selectionListener the selection listener
+ * @see org.eclipse.swt.widgets.Scale#addSelectionListener(org.eclipse.swt.events.SelectionListener)
+ */
+ public void addSelectionListener(final SelectionListener selectionListener) {
+ checkWidget();
+ selectionListeners.add(selectionListener);
+ }
+
+ /**
+ * Compute size.
+ *
+ * @param wHint the w hint
+ * @param hHint the h hint
+ * @param changed the changed
+ * @return the point
+ * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)
+ */
+ @Override
+ public Point computeSize(final int wHint, final int hHint, final boolean changed) {
+ checkWidget();
+ return new Point(WHOLE_RADIUS, WHOLE_RADIUS);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Widget#dispose()
+ */
+ @Override
+ public void dispose() {
+ super.dispose();
+ backgroundImage.dispose();
+ buttonFocus.dispose();
+ buttonNoFocus.dispose();
+ }
+
+ /**
+ * Gets the selection.
+ *
+ * @return the selection
+ * @see org.eclipse.swt.widgets.Scale#getSelection()
+ */
+ public int getSelection() {
+ checkWidget();
+ return selection;
+ }
+
+ /**
+ * Removes the selection listener.
+ *
+ * @param selectionListener the selection listener
+ * @see org.eclipse.swt.widgets.Scale#removeSelectionListener(org.eclipse.swt.events.SelectionListener)
+ */
+ public void removeSelectionListener(final SelectionListener selectionListener) {
+ checkWidget();
+ selectionListeners.remove(selectionListener);
+ }
+
+ /**
+ * Sets the enabled.
+ *
+ * @param enabled the new enabled
+ * @see org.eclipse.swt.widgets.Control#setEnabled(boolean)
+ */
+ @Override
+ public void setEnabled(final boolean enabled) {
+ super.setEnabled(enabled);
+ redraw();
+ }
+
+ /**
+ * Sets the selection.
+ *
+ * @param selection the new selection
+ * @see org.eclipse.swt.widgets.Scale#setSelection(int)
+ */
+ public void setSelection(final int selection) {
+ checkWidget();
+ if (selection < 0 || selection > 360) {
+ SWT.error(SWT.ERROR_CANNOT_SET_SELECTION);
+ }
+ this.selection = selection;
+ fireSelectionListeners(new Event());
+ redraw();
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/breadcrumb/Breadcrumb.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/breadcrumb/Breadcrumb.java
new file mode 100644
index 0000000..14c9931
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/breadcrumb/Breadcrumb.java
@@ -0,0 +1,396 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Laurent CARON. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.breadcrumb;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Widget;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class support the layout of selectable
+ * bar items displayed in a bread crumb.
+ * <p>
+ * The item children that may be added to instances of this class
+ * must be of type <code>BreadcrumbItem</code>.
+ * </p>
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ *
+ */
+public class Breadcrumb extends Canvas {
+
+ /** The Constant IS_BUTTON_PRESSED. */
+ private static final String IS_BUTTON_PRESSED = Breadcrumb.class.toString() + "_pressed";
+
+ /** The items. */
+ private final List<BreadcrumbItem> items;
+
+ /** The start gradient color. */
+ private static Color START_GRADIENT_COLOR = SWTGraphicUtil.getColorSafely(255, 255, 255);
+
+ /** The end gradient color. */
+ private static Color END_GRADIENT_COLOR = SWTGraphicUtil.getColorSafely(224, 224, 224);
+
+ /** The border color. */
+ static Color BORDER_COLOR = SWTGraphicUtil.getColorSafely(128, 128, 128);
+
+ /** The BORDE r_ colo r_1. */
+ static Color BORDER_COLOR_1 = SWTGraphicUtil.getColorSafely(212, 212, 212);
+
+ /** The BORDE r_ colo r_2. */
+ static Color BORDER_COLOR_2 = SWTGraphicUtil.getColorSafely(229, 229, 229);
+
+ /** The BORDE r_ colo r_3. */
+ static Color BORDER_COLOR_3 = SWTGraphicUtil.getColorSafely(243, 243, 243);
+
+ /** The has border. */
+ boolean hasBorder = false;
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a composite control which will be the parent of the new
+ * instance (cannot be null)
+ * @param style the style of control to construct
+ * @see Widget#getStyle()
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an
+ * allowed subclass</li>
+ * </ul>
+ */
+ public Breadcrumb(final Composite parent, final int style) {
+ super(parent, checkStyle(style) | SWT.DOUBLE_BUFFERED);
+ this.items = new ArrayList<BreadcrumbItem>();
+ this.hasBorder = (style & SWT.BORDER) != 0;
+ addListeners();
+ }
+
+ /**
+ * Check style.
+ *
+ * @param style the style
+ * @return the int
+ */
+ private static int checkStyle(final int style) {
+ if ((style & SWT.BORDER) != 0) {
+ return style & ~SWT.BORDER;
+ }
+ return 0;
+ }
+
+ /**
+ * Adds the listeners.
+ */
+ private void addListeners() {
+ addMouseDownListener();
+ addMouseUpListener();
+ addMouseHoverListener();
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(final PaintEvent e) {
+ Breadcrumb.this.paintControl(e);
+ }
+ });
+ }
+
+ /**
+ * Adds the mouse down listener.
+ */
+ private void addMouseDownListener() {
+ addListener(SWT.MouseDown, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ for (final BreadcrumbItem item : Breadcrumb.this.items) {
+ if (item.getBounds().contains(event.x, event.y)) {
+ final boolean isToggle = (item.getStyle() & SWT.TOGGLE) != 0;
+ final boolean isPush = (item.getStyle() & SWT.PUSH) != 0;
+ if (isToggle || isPush) {
+ item.setSelection(!item.getSelection());
+ redraw();
+ update();
+ }
+ item.setData(IS_BUTTON_PRESSED, "*");
+ return;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Adds the mouse up listener.
+ */
+ private void addMouseUpListener() {
+ addListener(SWT.MouseUp, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ for (final BreadcrumbItem item : Breadcrumb.this.items) {
+ if (item.getBounds().contains(event.x, event.y)) {
+ if (item.getData(IS_BUTTON_PRESSED) == null) {
+ // The button was not pressed
+ return;
+ }
+ item.setData(IS_BUTTON_PRESSED, null);
+
+ if ((item.getStyle() & SWT.PUSH) != 0) {
+ item.setSelection(false);
+ }
+
+ if ((item.getStyle() & (SWT.TOGGLE | SWT.PUSH)) != 0) {
+ item.fireSelectionEvent();
+ redraw();
+ update();
+ }
+ return;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Adds the mouse hover listener.
+ */
+ private void addMouseHoverListener() {
+ addListener(SWT.MouseHover, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ for (final BreadcrumbItem item : Breadcrumb.this.items) {
+ if (item.getBounds().contains(event.x, event.y)) {
+ setToolTipText(item.getTooltipText() == null ? "" : item.getTooltipText());
+ return;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Paint the component.
+ *
+ * @param e event
+ */
+ private void paintControl(final PaintEvent e) {
+ final GC gc = e.gc;
+ gc.setAdvanced(true);
+ gc.setAntialias(SWT.ON);
+
+ final int width = getSize().x;
+ final int height = getSize().y;
+
+ drawBackground(gc, width, height);
+ final Iterator<BreadcrumbItem> it = this.items.iterator();
+ int x = 0;
+ while (it.hasNext()) {
+ final BreadcrumbItem item = it.next();
+ item.setGc(gc).setToolbarHeight(height).setIsLastItemOfTheBreadCrumb(!it.hasNext());
+ item.drawButtonAtPosition(x);
+ x += item.getWidth();
+ }
+ }
+
+ /**
+ * Draw background.
+ *
+ * @param gc the gc
+ * @param width the width
+ * @param height the height
+ */
+ private void drawBackground(final GC gc, final int width, final int height) {
+ gc.setForeground(START_GRADIENT_COLOR);
+ gc.setBackground(END_GRADIENT_COLOR);
+ gc.fillGradientRectangle(0, 0, width, height, true);
+
+ if (this.hasBorder) {
+ gc.setForeground(BORDER_COLOR);
+ gc.drawRectangle(0, 0, width - 1, height - 1);
+ }
+ }
+
+ /**
+ * Add an item to the toolbar.
+ *
+ * @param item roundedToolItem to add
+ */
+ void addItem(final BreadcrumbItem item) {
+ this.items.add(item);
+ }
+
+ /**
+ *
+ *
+ * @param wHint the w hint
+ * @param hHint the h hint
+ * @param changed the changed
+ * @return the point
+ * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)
+ */
+ @Override
+ public Point computeSize(final int wHint, final int hHint, final boolean changed) {
+ int width = 0, height = 0;
+ for (final BreadcrumbItem item : this.items) {
+ width += item.getWidth();
+ height = Math.max(height, item.getHeight());
+ }
+ return new Point(Math.max(width, wHint), Math.max(height, hHint));
+ }
+
+ /**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public BreadcrumbItem getItem(final int index) {
+ checkWidget();
+ if (index < 0 || index > this.items.size()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ return this.items.get(index);
+ }
+
+ /**
+ * Returns the item at the given point in the receiver
+ * or null if no such item exists. The point is in the
+ * coordinate system of the receiver.
+ *
+ * @param point the point used to locate the item
+ * @return the item at the given point
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public BreadcrumbItem getItem(final Point point) {
+ checkWidget();
+ for (final BreadcrumbItem item : this.items) {
+ if (item.getBounds().contains(point)) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public int getItemCount() {
+ checkWidget();
+ return this.items.size();
+ }
+
+ /**
+ * Returns an array of <code>BreadcrumbItem</code>s which are the items
+ * in the receiver.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public BreadcrumbItem[] getItems() {
+ checkWidget();
+ return this.items.toArray(new BreadcrumbItem[this.items.size()]);
+ }
+
+ /**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param item the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public int indexOf(final BreadcrumbItem item) {
+ checkWidget();
+ return this.items.indexOf(item);
+ }
+
+ /**
+ * Remove an item to the toolbar.
+ *
+ * @param item item to remove
+ */
+ public void removeItem(final BreadcrumbItem item) {
+ this.items.remove(item);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/breadcrumb/BreadcrumbItem.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/breadcrumb/BreadcrumbItem.java
new file mode 100644
index 0000000..7b4c56d
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/breadcrumb/BreadcrumbItem.java
@@ -0,0 +1,1006 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Laurent CARON. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.breadcrumb;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Widget;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class represent a selectable user interface object that represents an item of a breadcrumb.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>TOGGLE,PUSH,NONE</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ *
+ */
+public class BreadcrumbItem extends Item {
+
+ /** The Constant MIN_WIDTH. */
+ private static final int MIN_WIDTH = 40;
+
+ /** The Constant MARGIN. */
+ private static final int MARGIN = 4;
+
+ /** The selected color. */
+ private static Color SELECTED_COLOR = SWTGraphicUtil.getColorSafely(223, 220, 213);
+
+ /** The parent breadcrumb. */
+ private final Breadcrumb parentBreadcrumb;
+
+ /** The selection listeners. */
+ private final List<SelectionListener> selectionListeners;
+
+ /** The bounds. */
+ private Rectangle bounds;
+
+ /** The enabled. */
+ private boolean enabled;
+
+ /** The selection. */
+ private boolean selection;
+
+ /** The width. */
+ private int width;
+
+ /** The height. */
+ private int height;
+
+ /** The disabled image. */
+ private Image disabledImage;
+
+ /** The selection image. */
+ private Image selectionImage;
+
+ /** The alignment. */
+ private int alignment;
+
+ /** The text color selected. */
+ private Color textColorSelected;
+
+ /** The text color. */
+ private Color textColor;
+
+ /** The tooltip text. */
+ private String tooltipText;
+
+ /** The gc. */
+ private GC gc;
+
+ /** The toolbar height. */
+ private int toolbarHeight;
+
+ /** The is last item of the bread crumb. */
+ private boolean isLastItemOfTheBreadCrumb;
+
+ /**
+ * Constructs a new instance of this class given its parent (which must be a
+ * <code>Breadcrumb</code>) and a style value describing its behavior and
+ * appearance. The item is added to the end of the items maintained by its
+ * parent.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a composite control which will be the parent of the new
+ * instance (cannot be null)
+ * @see Widget#getStyle
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an
+ * allowed subclass</li>
+ * </ul>
+ */
+ public BreadcrumbItem(final Breadcrumb parent) {
+ this(parent, SWT.NONE);
+ }
+
+ /**
+ * Constructs a new instance of this class given its parent (which must be a
+ * <code>Breadcrumb</code>) and a style value describing its behavior and
+ * appearance. The item is added to the end of the items maintained by its
+ * parent.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a composite control which will be the parent of the new
+ * instance (cannot be null)
+ * @param style the style of control to construct
+ * @see Widget#getStyle
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an
+ * allowed subclass</li>
+ * </ul>
+ */
+ public BreadcrumbItem(final Breadcrumb parent, final int style) {
+ super(parent, checkStyle(style));
+ parent.addItem(this);
+ this.parentBreadcrumb = parent;
+ this.textColor = parent.getDisplay().getSystemColor(SWT.COLOR_BLACK);
+ this.textColorSelected = parent.getDisplay().getSystemColor(SWT.COLOR_BLACK);
+ this.enabled = true;
+
+ if ((style & SWT.LEFT) != 0) {
+ this.alignment = SWT.LEFT;
+ }
+ if ((style & SWT.CENTER) != 0) {
+ this.alignment = SWT.CENTER;
+ }
+ if ((style & SWT.RIGHT) != 0) {
+ this.alignment = SWT.RIGHT;
+ }
+
+ this.selectionListeners = new ArrayList<SelectionListener>();
+ this.width = this.height = -1;
+ }
+
+ /**
+ * Check style.
+ *
+ * @param style the style
+ * @return the int
+ */
+ private static int checkStyle(int style) {
+ style = checkBits(style, SWT.NONE, SWT.PUSH, SWT.TOGGLE);
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
+ return checkBits(style, SWT.CENTER, SWT.LEFT, SWT.RIGHT);
+ }
+ return style;
+ }
+
+ /**
+ * Check bits.
+ *
+ * @param style the style
+ * @param int0 the int0
+ * @param int1 the int1
+ * @param int2 the int2
+ * @return the int
+ */
+ private static int checkBits(int style, final int int0, final int int1, final int int2) {
+ final int mask = int0 | int1 | int2;
+ if ((style & mask) == 0) {
+ style |= int0;
+ }
+ if ((style & int0) != 0) {
+ style = (style & ~mask) | int0;
+ }
+ if ((style & int1) != 0) {
+ style = (style & ~mask) | int1;
+ }
+ if ((style & int2) != 0) {
+ style = (style & ~mask) | int2;
+ }
+ return style;
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified
+ * when the control is selected by the user, by sending it one of the
+ * messages defined in the <code>SelectionListener</code> interface.
+ * <p>
+ * <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the control is
+ * selected by the user,
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void addSelectionListener(final SelectionListener listener) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ this.selectionListeners.add(listener);
+ }
+
+ /**
+ * Dispose.
+ *
+ * @see org.eclipse.swt.widgets.Widget#dispose()
+ */
+ @Override
+ public void dispose() {
+ getParent().removeItem(this);
+ this.bounds = null;
+ this.disabledImage = null;
+ this.selectionImage = null;
+ this.textColor = null;
+ this.textColorSelected = null;
+ super.dispose();
+ }
+
+ /**
+ * Returns a value which describes the position of the text in the receiver.
+ * The value will be one of <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>.
+ *
+ * @return the alignment
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public int getAlignment() {
+ checkWidget();
+ return this.alignment;
+ }
+
+ /**
+ * Returns a rectangle describing the receiver's size and location relative to its parent
+ * (or its display if its parent is null), unless the receiver is a shell.
+ * In this case, the location is relative to the display.
+ *
+ * @return the receiver's bounding rectangle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public Rectangle getBounds() {
+ checkWidget();
+ return this.bounds;
+ }
+
+ /**
+ * Gets the disabled image.
+ *
+ * @return the image displayed when the button is disabled
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Image getDisabledImage() {
+ checkWidget();
+ return this.disabledImage;
+ }
+
+ /**
+ * Returns <code>true</code> if the receiver is enabled, and
+ * <code>false</code> otherwise. A disabled control is typically not
+ * selectable from the user interface and draws with an inactive or "grayed"
+ * look.
+ *
+ * @return the receiver's enabled state
+ * @see #isEnabled
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public boolean getEnabled() {
+ checkWidget();
+ return this.enabled;
+ }
+
+ /**
+ * Returns the whole height of the item.
+ *
+ * @return the receiver's height
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public int getHeight() {
+ checkWidget();
+ if (this.height == -1) {
+ return computeDefaultSize().y;
+ }
+ return this.height;
+ }
+
+ /**
+ * Compute default size.
+ *
+ * @return the default size of the item
+ */
+ private Point computeDefaultSize() {
+ final Point sizeOfTextAndImages = computeSizeOfTextAndImages();
+ return new Point(2 * MARGIN + sizeOfTextAndImages.x, 2 * MARGIN + sizeOfTextAndImages.y);
+ }
+
+ /**
+ * Returns the receiver's parent, which must be a <code>Breadcrumb</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public Breadcrumb getParent() {
+ checkWidget();
+ return this.parentBreadcrumb;
+ }
+
+ /**
+ * Returns <code>true</code> if the receiver is selected, and false otherwise.
+ *
+ * @return the selection state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public boolean getSelection() {
+ checkWidget();
+ return this.selection;
+ }
+
+ /**
+ * Gets the selection image.
+ *
+ * @return the image displayed when the button is selected
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Image getSelectionImage() {
+ checkWidget();
+ return this.selectionImage;
+ }
+
+ /**
+ * Returns the color of the text when the button is enabled and not selected.
+ *
+ * @return the receiver's text color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public Color getTextColor() {
+ checkWidget();
+ return this.textColor;
+ }
+
+ /**
+ * Returns the color of the text when the button is not selected.
+ *
+ * @return the receiver's text color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+
+ public Color getTextColorSelected() {
+ checkWidget();
+ return this.textColorSelected;
+ }
+
+ /**
+ * Returns the receiver's tool tip text, or null if it has not been set.
+ *
+ * @return the receiver's tool tip text
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public String getTooltipText() {
+ checkWidget();
+ return this.tooltipText;
+ }
+
+ /**
+ * Returns the whole width of the item.
+ *
+ * @return the receiver's height
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public int getWidth() {
+ checkWidget();
+ if (this.width == -1) {
+ return Math.max(computeDefaultSize().x, MIN_WIDTH);
+ }
+ return Math.max(this.width, MIN_WIDTH);
+ }
+
+ /**
+ * Returns <code>true</code> if the receiver is enabled, and
+ * <code>false</code> otherwise. A disabled control is typically not
+ * selectable from the user interface and draws with an inactive or "grayed"
+ * look.
+ *
+ * @return the receiver's enabled state
+ * @see #getEnabled
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public boolean isEnabled() {
+ checkWidget();
+ return this.enabled;
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be
+ * notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ * @see SelectionListener
+ * @see #addSelectionListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void removeSelectionListener(final SelectionListener listener) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ this.selectionListeners.remove(listener);
+ }
+
+ /**
+ * Controls how text will be displayed in the receiver. The argument should
+ * be one of <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>.
+ *
+ * @param alignment the new alignment
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public void setAlignment(final int alignment) {
+ checkWidget();
+ this.alignment = alignment;
+ }
+
+ /**
+ * Sets the receiver's size and location to the rectangular area specified
+ * by the argument. The <code>x</code> and <code>y</code> fields of the
+ * rectangle are relative to the receiver's parent (or its display if its
+ * parent is null).
+ * <p>
+ * Note: Attempting to set the width or height of the receiver to a negative
+ * number will cause that value to be set to zero instead.
+ * </p>
+ *
+ * @param rectangle the new bounds
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setBounds(final Rectangle rectangle) {
+ checkWidget();
+ if (this.bounds == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ this.bounds = new Rectangle(Math.max(0, rectangle.x), //
+ Math.max(0, rectangle.y), //
+ Math.max(0, rectangle.width), //
+ Math.max(0, rectangle.height));
+ }
+
+ /**
+ * Sets the receiver's image to the argument when this is one is disabled, which may be null indicating that no image should be displayed.
+ *
+ * @param image the image to display on the receiver (may be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public void setDisabledImage(final Image image) {
+ checkWidget();
+ this.disabledImage = image;
+ }
+
+ /**
+ * Enables the receiver if the argument is <code>true</code>, and disables it otherwise.
+ * <p>
+ * A disabled control is typically not selectable from the user interface and draws with an inactive or "grayed" look.
+ * </p>
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public void setEnabled(final boolean enabled) {
+ checkWidget();
+ this.enabled = enabled;
+ }
+
+ /**
+ * Sets the height of the receiver.
+ * <p>
+ * Note: Attempting to set the width or height of the receiver to a negative number will cause that value to be set to zero
+ * instead.
+ * </p>
+ * @param height the new width
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public void setHeight(final int height) {
+ checkWidget();
+ this.height = Math.max(height, 0);
+ }
+
+ /**
+ * Sets the selection state of the receiver.
+ *
+ * @param selected the new selection state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public void setSelection(final boolean selected) {
+ checkWidget();
+ this.selection = selected;
+ }
+
+ /**
+ * Sets the receiver's image to the argument when this one is selected, which may be
+ * null indicating that no image should be displayed.
+ *
+ * @param image the image to display on the receiver (may be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public void setSelectionImage(final Image image) {
+ checkWidget();
+ this.selectionImage = image;
+ }
+
+ /**
+ * Sets the receiver's text color to the argument, which may be null indicating that no image should be displayed.
+ *
+ * @param textColor the text color to display on the receiver (may be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public void setTextColor(final Color textColor) {
+ checkWidget();
+ this.textColor = textColor;
+ }
+
+ /**
+ * Sets the receiver's text color to the argument when this one is selected, which may be null indicating that no image should be displayed.
+ *
+ * @param textColor the text color to display on the receiver (may be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public void setTextColorSelected(final Color textColor) {
+ checkWidget();
+ this.textColorSelected = textColor;
+ }
+
+ /**
+ * Sets the receiver's tool tip text to the argument, which may be null indicating
+ * that the default tool tip for the control will be shown. For a control that has
+ * a default tool tip, such as the Tree control on Windows, setting the tool tip text to an
+ * empty string replaces the default, causing no tool tip text to be shown.
+ * <p>
+ * The mnemonic indicator (character '&amp;') is not displayed in a tool tip. To display
+ * a single '&amp;' in the tool tip, the character '&amp;' can be escaped by doubling it in the string.
+ * </p>
+ *
+ * @param string the new tool tip text (or null)
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public void setTooltipText(final String string) {
+ checkWidget();
+ this.tooltipText = (string == null ? "" : string);
+ }
+
+ /**
+ * Sets the width of the receiver.
+ * <p>
+ * Note: Attempting to set the width or height of the receiver to a negative number will cause that value to be set to zero
+ * instead.
+ * </p>
+ * @param width the new width
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public void setWidth(final int width) {
+ checkWidget();
+ this.width = Math.max(0, width);
+ }
+
+ /**
+ * Fire selection event.
+ */
+ // --------------------------------------------- Package visibility section
+ void fireSelectionEvent() {
+ final Event event = new Event();
+ event.widget = this.parentBreadcrumb;
+ event.display = getDisplay();
+ event.item = this;
+ event.type = SWT.Selection;
+ for (final SelectionListener selectionListener : this.selectionListeners) {
+ selectionListener.widgetSelected(new SelectionEvent(event));
+ }
+ }
+
+ /**
+ * Draw button at position.
+ *
+ * @param x the x
+ */
+ void drawButtonAtPosition(final int x) {
+
+ if (this.selection) {
+ drawBackgroundAtPosition(x);
+ }
+ if (!this.isLastItemOfTheBreadCrumb) {
+ drawTrianglesAtPosition(x);
+ }
+
+ int xPosition = computeGap();
+ final Image drawnedImage = drawImageAtPosition(x + xPosition);
+ if (drawnedImage != null) {
+ xPosition += drawnedImage.getBounds().width + 2 * MARGIN;
+ }
+ drawTextAtPosition(x + xPosition);
+
+ this.bounds = new Rectangle(x, 0, getWidth(), this.toolbarHeight);
+ }
+
+ /**
+ * Draw background at position.
+ *
+ * @param x the x
+ */
+ private void drawBackgroundAtPosition(final int x) {
+ this.gc.setAdvanced(true);
+ this.gc.setAntialias(SWT.ON);
+
+ this.gc.setForeground(SELECTED_COLOR);
+ this.gc.setBackground(SELECTED_COLOR);
+
+ final boolean hasBorder = this.parentBreadcrumb.hasBorder;
+ final boolean isFirst = this.parentBreadcrumb.indexOf(this) == 0;
+ final int borderWidth = hasBorder ? 1 : 0;
+
+ int leftSide;
+ if (isFirst) {
+ leftSide = 0;
+ } else {
+ leftSide = 5 + (hasBorder ? 0 : 1);
+ }
+
+ final int xUpperLeft = x + borderWidth + leftSide;
+ final int yUpperLeft = borderWidth;
+ final int rectWidth = getWidth() - borderWidth - leftSide - (this.isLastItemOfTheBreadCrumb && hasBorder ? 1 : 0);
+ final int rectHeight = getHeight() - 2 * borderWidth;
+ this.gc.fillRectangle(xUpperLeft, yUpperLeft, rectWidth, rectHeight);
+
+ if (!isFirst) {
+ this.gc.fillPolygon(new int[] { xUpperLeft - 5, yUpperLeft, //
+ xUpperLeft, yUpperLeft, //
+ xUpperLeft, yUpperLeft + this.toolbarHeight / 2 //
+ });
+ this.gc.fillPolygon(new int[] { xUpperLeft - 5, yUpperLeft + rectHeight, //
+ xUpperLeft, yUpperLeft + rectHeight, //
+ xUpperLeft, yUpperLeft + this.toolbarHeight / 2 //
+ });
+
+ }
+
+ if (!this.isLastItemOfTheBreadCrumb) {
+ this.gc.fillPolygon(new int[] { xUpperLeft + rectWidth, yUpperLeft + 1, //
+ xUpperLeft + rectWidth, yUpperLeft + getHeight(), //
+ xUpperLeft + rectWidth + 5, yUpperLeft + this.toolbarHeight / 2 //
+ });
+ }
+
+ this.gc.setClipping((Rectangle) null);
+ }
+
+ /**
+ * Draw triangles at position.
+ *
+ * @param x the x
+ */
+ private void drawTrianglesAtPosition(final int x) {
+ this.gc.setForeground(Breadcrumb.BORDER_COLOR);
+ drawTriangleAtPosition(x + getWidth());
+
+ this.gc.setAlpha(127);
+ this.gc.setForeground(Breadcrumb.BORDER_COLOR_1);
+ drawTriangleAtPosition(x + getWidth() + 1);
+
+ this.gc.setForeground(Breadcrumb.BORDER_COLOR_2);
+ drawTriangleAtPosition(x + getWidth() + 2);
+
+ this.gc.setForeground(Breadcrumb.BORDER_COLOR_3);
+ drawTriangleAtPosition(x + getWidth() + 3);
+
+ this.gc.setAlpha(255);
+ if (this.parentBreadcrumb.hasBorder) {
+ this.gc.setForeground(Breadcrumb.BORDER_COLOR);
+ this.gc.drawLine(x + getWidth(), 0, x + getWidth() + 3, 0);
+ this.gc.drawLine(x + getWidth(), this.toolbarHeight - 1, x + getWidth() + 3, this.toolbarHeight - 1);
+ }
+ }
+
+ /**
+ * Draw triangle at position.
+ *
+ * @param x the x
+ */
+ private void drawTriangleAtPosition(final int x) {
+ this.gc.drawLine(x, 0, x + 5, this.toolbarHeight / 2);
+ this.gc.drawLine(x + 5, this.toolbarHeight / 2, x, this.toolbarHeight);
+
+ }
+
+ /**
+ * Compute gap.
+ *
+ * @return the int
+ */
+ private int computeGap() {
+ final int widthOfTextAndImage = computeSizeOfTextAndImages().x;
+ switch (this.alignment) {
+ case SWT.CENTER:
+ return (getWidth() - widthOfTextAndImage) / 2;
+ case SWT.RIGHT:
+ return getWidth() - widthOfTextAndImage - MARGIN;
+ default:
+ return MARGIN;
+ }
+ }
+
+ /**
+ * Compute size of text and images.
+ *
+ * @return the point
+ */
+ private Point computeSizeOfTextAndImages() {
+ int width = 0, height = 0;
+ final boolean textISNotEmpty = getText() != null && !getText().equals("");
+
+ if (textISNotEmpty) {
+ final GC gc = new GC(this.parentBreadcrumb);
+ gc.setFont(this.parentBreadcrumb.getFont());
+ final Point extent = gc.stringExtent(getText());
+ gc.dispose();
+ width += extent.x;
+ height = extent.y;
+ }
+
+ final Point imageSize = computeMaxWidthAndHeightForImages(getImage(), this.selectionImage, this.disabledImage);
+
+ if (imageSize.x != -1) {
+ width += imageSize.x;
+ height = Math.max(imageSize.y, height);
+ if (textISNotEmpty) {
+ width += MARGIN * 2;
+ }
+ }
+ width += MARGIN;
+ return new Point(width, height);
+ }
+
+ /**
+ * Compute max width and height for images.
+ *
+ * @param images the images
+ * @return the point
+ */
+ private Point computeMaxWidthAndHeightForImages(final Image... images) {
+ final Point imageSize = new Point(-1, -1);
+ for (final Image image : images) {
+ if (image == null) {
+ continue;
+ }
+ final Rectangle imageBounds = image.getBounds();
+ imageSize.x = Math.max(imageBounds.width, imageSize.x);
+ imageSize.y = Math.max(imageBounds.height, imageSize.y);
+ }
+ return imageSize;
+ }
+
+ /**
+ * Draw image at position.
+ *
+ * @param xPosition the x position
+ * @return the image
+ */
+ private Image drawImageAtPosition(final int xPosition) {
+ Image image;
+ if (!isEnabled()) {
+ image = this.disabledImage;
+ } else if (this.selection) {
+ image = this.selectionImage;
+ } else {
+ image = getImage();
+ }
+
+ if (image == null) {
+ return null;
+ }
+
+ final int yPosition = (this.toolbarHeight - image.getBounds().height) / 2;
+ this.gc.drawImage(image, (int) (xPosition + MARGIN * 1.5), yPosition);
+ return image;
+ }
+
+ /**
+ * Draw text at position.
+ *
+ * @param xPosition the x position
+ */
+ private void drawTextAtPosition(final int xPosition) {
+ this.gc.setFont(this.parentBreadcrumb.getFont());
+ if (this.selection) {
+ this.gc.setForeground(this.textColorSelected);
+ } else {
+ this.gc.setForeground(this.textColor);
+ }
+
+ final Point textSize = this.gc.stringExtent(getText());
+ final int yPosition = (this.toolbarHeight - textSize.y) / 2;
+
+ int padding;
+ if (this.parentBreadcrumb.indexOf(this) == 0 || this.isLastItemOfTheBreadCrumb) {
+ padding = 0;
+ } else {
+ padding = 5;
+ }
+ this.gc.drawText(getText(), xPosition + padding, yPosition, true);
+ }
+
+ /**
+ * Sets the gc.
+ *
+ * @param gc the gc
+ * @return the breadcrumb item
+ */
+ BreadcrumbItem setGc(final GC gc) {
+ this.gc = gc;
+ return this;
+ }
+
+ /**
+ * Sets the toolbar height.
+ *
+ * @param toolbarHeight the toolbar height
+ * @return the breadcrumb item
+ */
+ BreadcrumbItem setToolbarHeight(final int toolbarHeight) {
+ this.toolbarHeight = toolbarHeight;
+ return this;
+ }
+
+ /**
+ * Sets the is last item of the bread crumb.
+ *
+ * @param isLastItemOfTheBreadCrumb the is last item of the bread crumb
+ * @return the breadcrumb item
+ */
+ BreadcrumbItem setIsLastItemOfTheBreadCrumb(final boolean isLastItemOfTheBreadCrumb) {
+ this.isLastItemOfTheBreadCrumb = isLastItemOfTheBreadCrumb;
+ return this;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/brushedMetalComposite/BrushedMetalComposite.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/brushedMetalComposite/BrushedMetalComposite.java
new file mode 100644
index 0000000..e25335f
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/brushedMetalComposite/BrushedMetalComposite.java
@@ -0,0 +1,428 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.brushedMetalComposite;
+
+import java.util.Random;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Widget;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are controls which background's texture is brushed
+ * metal "a la Mac"
+ * This work is inspired by the article "Creating a brushed metal texture" by Jerry Huxtable (http://www.jhlabs.com/ip/brushed_metal.html)
+ */
+public class BrushedMetalComposite extends Composite {
+
+ /** The old image. */
+ private Image oldImage;
+
+ /** The radius. */
+ private int radius = 10;
+
+ /** The amount. */
+ private float amount = 0.1f;
+
+ /** The color. */
+ private int color = 0xff888888;
+
+ /** The shine. */
+ private float shine = 0.1f;
+
+ /** The monochrome. */
+ private boolean monochrome = true;
+
+ /** The random numbers. */
+ private Random randomNumbers;
+
+ /** The palette. */
+ private final PaletteData palette = new PaletteData(0xFF0000, 0x00FF00, 0x0000FF);
+
+ /** The image data. */
+ private ImageData imageData;
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance
+ * (cannot be null)
+ * @param style the style of widget to construct
+ * @see Composite#Composite(Composite, int)
+ * @see SWT#NO_BACKGROUND
+ * @see SWT#NO_FOCUS
+ * @see SWT#NO_MERGE_PAINTS
+ * @see SWT#NO_REDRAW_RESIZE
+ * @see SWT#NO_RADIO_GROUP
+ * @see SWT#EMBEDDED
+ * @see SWT#DOUBLE_BUFFERED
+ * @see Widget#getStyle
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ public BrushedMetalComposite(final Composite parent, final int style) {
+ super(parent, style);
+ addListeners(parent);
+ }
+
+ /**
+ * Adds the listeners.
+ *
+ * @param parent the parent
+ */
+ private void addListeners(final Composite parent) {
+ this.addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ createBrushedMetalBackground();
+ paintControl();
+ }
+ });
+
+ parent.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ SWTGraphicUtil.safeDispose(BrushedMetalComposite.this.oldImage);
+ }
+ });
+ }
+
+ /**
+ * Paint the component.
+ */
+ private void paintControl() {
+ final Display display = getDisplay();
+ final Image newImage = new Image(display, this.imageData);
+
+ setBackgroundImage(newImage);
+ SWTGraphicUtil.safeDispose(this.oldImage);
+ this.oldImage = newImage;
+ }
+
+ /**
+ * Create a brushed metal background.
+ *
+ * @return an image data that contains the background
+ */
+ private void createBrushedMetalBackground() {
+
+ final Rectangle rect = getClientArea();
+ final int width = Math.max(1, rect.width);
+ final int height = Math.max(1, rect.width);
+
+ final int[] inPixels = new int[width];
+
+ this.imageData = new ImageData(width, height, 0x20, this.palette);
+
+ this.randomNumbers = new Random(0);
+ final int a = this.color & 0xff000000;
+ final int r = this.color >> 16 & 0xff;
+ final int g = this.color >> 8 & 0xff;
+ final int b = this.color & 0xff;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int tr = r;
+ int tg = g;
+ int tb = b;
+ if ( Float.compare( this.shine, (float) 0.0 ) != 0 ) {
+ final int f = (int) (255 * this.shine * Math.sin((double) x / width * Math.PI));
+ tr += f;
+ tg += f;
+ tb += f;
+ }
+ if (this.monochrome) {
+ final int n = (int) (255 * (2 * this.randomNumbers.nextFloat() - 1) * this.amount);
+ inPixels[x] = a | this.clamp(tr + n) << 16 | this.clamp(tg + n) << 8 | this.clamp(tb + n);
+ } else {
+ inPixels[x] = a | this.random(tr) << 16 | this.random(tg) << 8 | this.random(tb);
+ }
+ }
+
+ if (this.radius != 0) {
+ setDataElements(0, y, width, 1, this.blur(inPixels, width, this.radius));
+ } else {
+ setDataElements(0, y, width, 1, inPixels);
+ }
+ }
+
+ }
+
+ /**
+ * Sets the data for a rectangle of pixels from a primitive array.
+ *
+ * @param posX The X coordinate of the upper left pixel location.
+ * @param posY The Y coordinate of the upper left pixel location.
+ * @param width Width of the pixel rectangle.
+ * @param height Height of the pixel rectangle
+ * @param pixels An array containing the pixel data to place between x,y and
+ * x+w-1, y+h-1.
+ */
+ private void setDataElements(final int posX, final int posY, final int width, final int height, final int[] pixels) {
+ int cpt = 0;
+ for (int y = posY; y < posY + height; y++) {
+ for (int x = posX; x < posX + width; x++) {
+ final int rgb = pixels[cpt++];
+ final int pixel = this.palette.getPixel(new RGB(rgb >> 16 & 0xFF, rgb >> 8 & 0xFF, rgb & 0xFF));
+ this.imageData.setPixel(x, y, pixel);
+ this.imageData.setAlpha(x, y, rgb >> 24 & 0xFF);
+ }
+ }
+ }
+
+ /**
+ * Add a random number to the value. The result is between 0 and 255
+ *
+ * @param x the initial value
+ * @return the int
+ */
+ private int random(int x) {
+ x += (int) (255 * (2 * this.randomNumbers.nextFloat() - 1) * this.amount);
+ if (x < 0) {
+ x = 0;
+ } else if (x > 0xff) {
+ x = 0xff;
+ }
+ return x;
+ }
+
+ /**
+ * Clamp a number between 0 and 255.
+ *
+ * @param c the number to clamp
+ * @return the number. If c is negative, returns 0. If c is greater than
+ * 255, returns 255.
+ */
+ private int clamp(final int c) {
+ if (c < 0) {
+ return 0;
+ }
+
+ if (c > 255) {
+ return 255;
+ }
+
+ return c;
+ }
+
+ /**
+ * Apply a blur filter to an array of int that represents and image which
+ * size is width columns * 1 row.
+ *
+ * @param in the array of int that represents the image
+ * @param width the width of the image
+ * @param radius the "radius" blur parameter
+ * @return the int[]
+ */
+ private int[] blur(final int[] in, final int width, final int radius) {
+ final int[] out = new int[width];
+ final int widthMinus1 = width - 1;
+ final int r2 = 2 * radius + 1;
+ int tr = 0, tg = 0, tb = 0;
+
+ for (int i = -radius; i <= radius; i++) {
+ final int rgb = in[this.mod(i, width)];
+ tr += rgb >> 16 & 0xff;
+ tg += rgb >> 8 & 0xff;
+ tb += rgb & 0xff;
+ }
+
+ for (int x = 0; x < width; x++) {
+ out[x] = 0xff000000 | tr / r2 << 16 | tg / r2 << 8 | tb / r2;
+
+ int i1 = x + radius + 1;
+ if (i1 > widthMinus1) {
+ i1 = this.mod(i1, width);
+ }
+ int i2 = x - radius;
+ if (i2 < 0) {
+ i2 = this.mod(i2, width);
+ }
+ final int rgb1 = in[i1];
+ final int rgb2 = in[i2];
+
+ tr += (rgb1 & 0xff0000) - (rgb2 & 0xff0000) >> 16;
+ tg += (rgb1 & 0xff00) - (rgb2 & 0xff00) >> 8;
+ tb += (rgb1 & 0xff) - (rgb2 & 0xff);
+ }
+ return out;
+ }
+
+ /**
+ * Return a mod b. This differs from the % operator with respect to negative
+ * numbers.
+ *
+ * @param a the dividend
+ * @param b the divisor
+ * @return a mod b
+ */
+ private int mod(int a, final int b) {
+ final int n = a / b;
+
+ a -= n * b;
+ if (a < 0) {
+ return a + b;
+ }
+ return a;
+ }
+
+ // ------------------------------------ Getters and Setters
+
+ /**
+ * Gets the radius.
+ *
+ * @return the "radius" of the blur
+ */
+ public int getRadius() {
+ return this.radius;
+ }
+
+ /**
+ * Sets the radius.
+ *
+ * @param radius the "radius" of the blur
+ */
+ public void setRadius(final int radius) {
+ this.radius = radius;
+ createBrushedMetalBackground();
+ paintControl();
+ }
+
+ /**
+ * Gets the amount.
+ *
+ * @return the amount of noise to add
+ */
+ public float getAmount() {
+ return this.amount;
+ }
+
+ /**
+ * Sets the amount.
+ *
+ * @param amount the amount of noise to add
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the value is not between 0
+ * and 1 inclusive</li>
+ * </ul>
+ */
+ public void setAmount(final float amount) {
+ if (amount < 0f || amount > 1f) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.amount = amount;
+ createBrushedMetalBackground();
+ paintControl();
+ }
+
+ /**
+ * Gets the color.
+ *
+ * @return the color of the metal. Please notice that this color is a new
+ * SWT object, so it has to be disposed !
+ */
+ public Color getColor() {
+ return new Color(this.getDisplay(), this.color >> 16 & 0xFF, this.color >> 8 & 0xFF, this.color & 0xFF);
+ }
+
+ /**
+ * Sets the color.
+ *
+ * @param color the color to set
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the value is null</li>
+ * </ul>
+ */
+ public void setColor(final Color color) {
+ if (color == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ return; // to satisfy SONAR
+ }
+ this.color = 0xFF << 24 | color.getRed() << 16 | color.getGreen() << 8 | color.getBlue();
+ createBrushedMetalBackground();
+ ;
+ paintControl();
+ }
+
+ /**
+ * Gets the shine.
+ *
+ * @return the shine to add
+ */
+ public float getShine() {
+ return this.shine;
+ }
+
+ /**
+ * Sets the shine.
+ *
+ * @param shine the shine to set
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the value is not between 0
+ * and 1 inclusive</li>
+ * </ul>
+ */
+ public void setShine(final float shine) {
+ if (this.amount < 0f || this.amount > 1f) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.shine = shine;
+ createBrushedMetalBackground();
+ paintControl();
+ }
+
+ /**
+ * Checks if is monochrome.
+ *
+ * @return the monochrome
+ */
+ public boolean isMonochrome() {
+ return this.monochrome;
+ }
+
+ /**
+ * Sets the monochrome.
+ *
+ * @param monochrome the monochrome to set
+ */
+ public void setMonochrome(final boolean monochrome) {
+ this.monochrome = monochrome;
+ createBrushedMetalBackground();
+ paintControl();
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/Calculator.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/Calculator.java
new file mode 100644
index 0000000..b1d24c2
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/Calculator.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.calculator;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+/**
+ * Instances of this class are calculator.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * This component is inspired by Hermant (http://www.javabeginner.com/java-swing/java-swing-calculator)
+ */
+public class Calculator extends Composite {
+
+ /** The display area. */
+ private final Label displayArea;
+
+ /** The panel. */
+ private final CalculatorButtonsComposite panel;
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a composite control which will be the parent of the new
+ * instance (cannot be null)
+ * @param style the style of control to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ *
+ */
+ public Calculator(final Composite parent, final int style) {
+ super(parent, style);
+ setLayout(new GridLayout());
+ this.displayArea = createTextArea();
+ this.panel = new CalculatorButtonsComposite(this, SWT.NONE);
+ this.panel.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+ this.panel.setDisplayArea(this.displayArea);
+ this.displayArea.addKeyListener(this.panel.getKeyListener());
+ }
+
+ /**
+ * Create the text area.
+ *
+ * @return the label
+ */
+ private Label createTextArea() {
+ final Label text = new Label(this, SWT.BORDER | SWT.RIGHT);
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, false);
+ gd.widthHint = 150;
+ text.setLayoutData(gd);
+ text.setText("0");
+ text.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ return text;
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified
+ * when the receiver's text is modified, by sending it one of the messages
+ * defined in the <code>ModifyListener</code> interface.
+ *
+ * @param listener the listener which should be notified
+ * @see ModifyListener
+ * @see #removeModifyListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void addModifyListener(final ModifyListener listener) {
+ checkWidget();
+ this.panel.addModifyListener(listener);
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value
+ */
+ public String getValue() {
+ checkWidget();
+ return this.displayArea.getText();
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be
+ * notified when the receiver's text is modified.
+ *
+ * @param listener the listener which should no longer be notified
+ * @see ModifyListener
+ * @see #addModifyListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void removeModifyListener(final ModifyListener listener) {
+ checkWidget();
+ this.panel.removeModifyListener(listener);
+ }
+
+ /**
+ * Sets the value.
+ *
+ * @param value new value
+ * @throws NumberFormatException if <code>value</code> is not a valid float
+ * value
+ */
+ public void setValue(final String value) {
+ checkWidget();
+ this.displayArea.setText(value);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorButtonsComposite.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorButtonsComposite.java
new file mode 100644
index 0000000..c99964d
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorButtonsComposite.java
@@ -0,0 +1,489 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.calculator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This composite contains all buttons.
+ */
+class CalculatorButtonsComposite extends Composite {
+
+ /** The Constant LABEL_C. */
+ private static final String LABEL_C = "C";
+
+ /** The Constant LABEL_CE. */
+ private static final String LABEL_CE = "CE";
+
+ /** The Constant LABEL_BACK. */
+ private static final String LABEL_BACK = "Back";
+
+ /** The dark red color. */
+ private final Color darkRedColor;
+
+ /** The dark blue color. */
+ private final Color darkBlueColor;
+
+ /** The engine. */
+ private final CalculatorEngine engine;
+
+ /** The display area. */
+ private Label displayArea;
+
+ /** The key listener. */
+ private KeyListener keyListener;
+
+ /** The modify listeners. */
+ private final List<ModifyListener> modifyListeners;
+
+ /**
+ * Constructor.
+ *
+ * @param parent parent composite
+ * @param style style
+ */
+ CalculatorButtonsComposite(final Composite parent, final int style) {
+ super(parent, style);
+ setLayout(new GridLayout(5, false));
+ this.darkRedColor = new Color(getDisplay(), 139, 0, 0);
+ this.darkBlueColor = new Color(getDisplay(), 0, 0, 139);
+ createButtons();
+
+ SWTGraphicUtil.addDisposer(this, this.darkBlueColor);
+ SWTGraphicUtil.addDisposer(this, this.darkRedColor);
+
+ this.engine = new CalculatorEngine(this);
+ addKeyListeners();
+ this.modifyListeners = new ArrayList<ModifyListener>();
+ }
+
+ /**
+ * Create all buttons.
+ */
+ private void createButtons() {
+ final Button buttonBackSpace = createButton(LABEL_BACK, this.darkRedColor);
+ buttonBackSpace.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false, 3, 1));
+ buttonBackSpace.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.processBackSpace();
+ }
+ });
+
+ final Button buttonCe = createButton(LABEL_CE, this.darkRedColor);
+ buttonCe.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.clearResult();
+ }
+ });
+
+ final Button buttonC = createButton(LABEL_C, this.darkRedColor);
+ buttonC.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.clearWholeContent();
+ }
+ });
+
+ createDigitButton(7);
+ createDigitButton(8);
+ createDigitButton(9);
+
+ final Button buttonDivide = createButton(CalculatorEngine.OPERATOR_DIVIDE, getDisplay().getSystemColor(SWT.COLOR_RED));
+ buttonDivide.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_DIVIDE);
+ }
+ });
+
+ final Button buttonSqrt = createButton("\u221A", this.darkRedColor);
+ buttonSqrt.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.processSquareRootOperation();
+ }
+ });
+
+ createDigitButton(4);
+ createDigitButton(5);
+ createDigitButton(6);
+
+ final Button buttonMultiply = createButton(CalculatorEngine.OPERATOR_MULTIPLY, getDisplay().getSystemColor(SWT.COLOR_RED));
+ buttonMultiply.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_MULTIPLY);
+ }
+ });
+ final Button buttonInverse = createButton("1/x", this.darkBlueColor);
+ buttonInverse.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.processInverseOperation();
+ }
+ });
+
+ createDigitButton(1);
+ createDigitButton(2);
+ createDigitButton(3);
+
+ final Button buttonMinus = createButton(CalculatorEngine.OPERATOR_MINUS, getDisplay().getSystemColor(SWT.COLOR_RED));
+ buttonMinus.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_MINUS);
+ }
+ });
+
+ final Button buttonPercent = createButton("%", this.darkBlueColor);
+ buttonPercent.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.processPerCentageOperation();
+ }
+ });
+
+ createDigitButton(0);
+
+ final Button buttonPlusMinus = createButton("+/-", getDisplay().getSystemColor(SWT.COLOR_BLUE));
+ buttonPlusMinus.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.processSignChange();
+ }
+ });
+ final Button buttonDot = createButton(".", getDisplay().getSystemColor(SWT.COLOR_BLUE));
+ buttonDot.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.addDecimalPoint();
+ }
+ });
+
+ final Button buttonPlus = createButton(CalculatorEngine.OPERATOR_PLUS, getDisplay().getSystemColor(SWT.COLOR_RED));
+ buttonPlus.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_PLUS);
+ }
+ });
+
+ final Button buttonEquals = createButton("=", getDisplay().getSystemColor(SWT.COLOR_RED));
+ buttonEquals.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.processEquals();
+ }
+ });
+ }
+
+ /**
+ * Creates the digit button.
+ *
+ * @param digit the digit
+ */
+ private void createDigitButton(final int digit) {
+ final Button button = createButton(" " + digit + " ", getDisplay().getSystemColor(SWT.COLOR_BLUE));
+ button.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ CalculatorButtonsComposite.this.engine.addDigitToDisplay(digit);
+ }
+ });
+
+ }
+
+ /**
+ * Creates the button.
+ *
+ * @param label the label
+ * @param color the color
+ * @return the button
+ */
+ private Button createButton(final String label, final Color color) {
+ final Button button = new Button(this, SWT.PUSH | SWT.DOUBLE_BUFFERED);
+ button.setText("");
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, false, false);
+ gd.widthHint = 30;
+ button.setLayoutData(gd);
+
+ // Use a paint listener because setForeground is not working on Windows
+ button.addPaintListener(new PaintListener() {
+
+ @Override
+ public void paintControl(final PaintEvent e) {
+ e.gc.setForeground(color);
+ e.gc.setFont(getFont());
+ final Point textSize = e.gc.textExtent(" " + label + " ", SWT.TRANSPARENT);
+ e.gc.drawText(" " + label + " ", (button.getBounds().width - textSize.x) / 2, (button.getBounds().height - textSize.y) / 2, true);
+ }
+ });
+
+ return button;
+ }
+
+ /**
+ * Add key listeners.
+ */
+ private void addKeyListeners() {
+ this.keyListener = new KeyAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.KeyAdapter#keyReleased(org.eclipse.swt.events.KeyEvent)
+ */
+ @Override
+ public void keyReleased(final KeyEvent e) {
+ switch (e.character) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ CalculatorButtonsComposite.this.engine.addDigitToDisplay(Integer.parseInt(String.valueOf(e.character)));
+ return;
+ case '.':
+ CalculatorButtonsComposite.this.engine.addDecimalPoint();
+ return;
+ case '+':
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_PLUS);
+ return;
+ case '-':
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_MINUS);
+ return;
+ case '*':
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_MULTIPLY);
+ return;
+ case '/':
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_DIVIDE);
+ return;
+ case '=':
+ CalculatorButtonsComposite.this.engine.processEquals();
+ return;
+ case '%':
+ CalculatorButtonsComposite.this.engine.processPerCentageOperation();
+ return;
+
+ }
+
+ switch (e.keyCode) {
+ case SWT.KEYPAD_0:
+ case SWT.KEYPAD_1:
+ case SWT.KEYPAD_2:
+ case SWT.KEYPAD_3:
+ case SWT.KEYPAD_4:
+ case SWT.KEYPAD_5:
+ case SWT.KEYPAD_6:
+ case SWT.KEYPAD_7:
+ case SWT.KEYPAD_8:
+ case SWT.KEYPAD_9:
+ final int digit = e.keyCode - SWT.KEYCODE_BIT - 47;
+ CalculatorButtonsComposite.this.engine.addDigitToDisplay(digit);
+ return;
+ case SWT.KEYPAD_ADD:
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_PLUS);
+ return;
+ case SWT.KEYPAD_SUBTRACT:
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_MINUS);
+ return;
+ case SWT.KEYPAD_DIVIDE:
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_DIVIDE);
+ return;
+ case SWT.KEYPAD_MULTIPLY:
+ CalculatorButtonsComposite.this.engine.processOperation(CalculatorEngine.OPERATOR_MULTIPLY);
+ return;
+ case SWT.KEYPAD_CR:
+ case SWT.KEYPAD_EQUAL:
+ case SWT.CR:
+ CalculatorButtonsComposite.this.engine.processEquals();
+ return;
+ case SWT.KEYPAD_DECIMAL:
+ CalculatorButtonsComposite.this.engine.addDecimalPoint();
+ return;
+ case SWT.BS:
+ CalculatorButtonsComposite.this.engine.processBackSpace();
+ return;
+ case SWT.ESC:
+ CalculatorButtonsComposite.this.engine.clearWholeContent();
+ return;
+ }
+ }
+ };
+
+ for (final Control control : this.getChildren()) {
+ control.addKeyListener(this.keyListener);
+ }
+ addKeyListener(this.keyListener);
+
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified
+ * when the receiver's text is modified, by sending it one of the messages
+ * defined in the <code>ModifyListener</code> interface.
+ *
+ * @param listener the listener which should be notified
+ * @see ModifyListener
+ * @see #removeModifyListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void addModifyListener(final ModifyListener listener) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ this.modifyListeners.add(listener);
+ }
+
+ /**
+ * Fire the modify listeners.
+ */
+ void fireModifyListeners() {
+ for (final ModifyListener listener : this.modifyListeners) {
+ final Event e = new Event();
+ e.widget = this;
+ final ModifyEvent modifyEvent = new ModifyEvent(e);
+ listener.modifyText(modifyEvent);
+ }
+ }
+
+ /**
+ * Gets the key listener.
+ *
+ * @return the keyListener
+ */
+ KeyListener getKeyListener() {
+ return this.keyListener;
+ }
+
+ /**
+ * Gets the display area.
+ *
+ * @return the text
+ */
+ Label getDisplayArea() {
+ return this.displayArea;
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be
+ * notified when the receiver's text is modified.
+ *
+ * @param listener the listener which should no longer be notified
+ * @see ModifyListener
+ * @see #addModifyListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void removeModifyListener(final ModifyListener listener) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ this.modifyListeners.remove(listener);
+ }
+
+ /**
+ * Sets the display area.
+ *
+ * @param text the text to set
+ */
+ void setDisplayArea(final Label text) {
+ this.displayArea = text;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorCombo.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorCombo.java
new file mode 100644
index 0000000..63a2d1c
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorCombo.java
@@ -0,0 +1,475 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial API and implementation
+ *******************************************************************************/
+
+package org.mihalis.opal.calculator;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * The CalculatorCombo class represents a selectable user interface object that
+ * combines a text field and a calculator buttons panel and issues notification
+ * when an the value is modified.
+ * <p>
+ * Note that although this class is a subclass of <code>Composite</code>, it
+ * does not make sense to add children to it, or set a layout on it.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b>
+ * <dd>BORDER, FLAT</dd>
+ * <dt><b>Events:</b>
+ * <dd>Modify</dd>
+ * </dl>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#ccombo">CCombo
+ * snippets</a>
+ */
+public class CalculatorCombo extends Composite {
+
+ /** The label. */
+ private Label label;
+
+ /** The arrow. */
+ private Button arrow;
+
+ /** The popup. */
+ private Shell popup;
+
+ /** The filter. */
+ private Listener listener, filter;
+
+ /** The has focus. */
+ private boolean hasFocus;
+
+ /** The key listener. */
+ private KeyListener keyListener;
+
+ /** The composite. */
+ private CalculatorButtonsComposite composite;
+
+ /**
+ * Constructs a new instance of this class given its parent.
+ *
+ * @param parent a widget which will be the parent of the new instance (cannot be null)
+ * @param style not used
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ public CalculatorCombo(final Composite parent, final int style) {
+ super(parent, style);
+
+ final GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = gridLayout.marginWidth = gridLayout.marginHeight = 0;
+ this.setLayout(gridLayout);
+
+ this.label = new Label(this, SWT.BORDER | SWT.RIGHT);
+ this.label.setBackground(this.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+ this.label.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+
+ this.arrow = new Button(this, SWT.ARROW | SWT.DOWN);
+ this.arrow.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+
+ this.listener = new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ if (CalculatorCombo.this.popup == event.widget) {
+ handlePopupEvent(event);
+ return;
+ }
+
+ if (CalculatorCombo.this.arrow == event.widget) {
+ handleButtonEvent(event);
+ return;
+ }
+
+ if (CalculatorCombo.this == event.widget) {
+ handleMultiChoiceEvent(event);
+ return;
+ }
+
+ if (getShell() == event.widget) {
+ getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (isDisposed()) {
+ return;
+ }
+ handleFocusEvent(SWT.FocusOut);
+ }
+ });
+ }
+ }
+ };
+
+ final int[] calculatorComboEvents = { SWT.Dispose, SWT.Move, SWT.Resize };
+ for (final int calculatorComboEvent : calculatorComboEvents) {
+ this.addListener(calculatorComboEvent, this.listener);
+ }
+
+ final int[] buttonEvents = { SWT.Selection, SWT.FocusIn };
+ for (final int buttonEvent : buttonEvents) {
+ this.arrow.addListener(buttonEvent, this.listener);
+ }
+
+ this.filter = new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ final Shell shell = ((Control) event.widget).getShell();
+ if (shell == CalculatorCombo.this.getShell()) {
+ handleFocusEvent(SWT.FocusOut);
+ }
+ }
+ };
+
+ createPopupShell();
+ }
+
+ /**
+ * Handle a popup event.
+ *
+ * @param event event to handle
+ */
+ private void handlePopupEvent(final Event event) {
+ switch (event.type) {
+ case SWT.Paint:
+ final Rectangle listRect = this.popup.getBounds();
+ final Color black = getDisplay().getSystemColor(SWT.COLOR_BLACK);
+ event.gc.setForeground(black);
+ event.gc.drawRectangle(0, 0, listRect.width - 1, listRect.height - 1);
+ break;
+ case SWT.Close:
+ event.doit = false;
+ hidePopupWindow(false);
+ break;
+ case SWT.Deactivate:
+ hidePopupWindow(false);
+ break;
+ case SWT.Dispose:
+ if (this.keyListener != null) {
+ this.label.removeKeyListener(this.keyListener);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Hide popup window.
+ *
+ * @param drop the drop
+ */
+ private void hidePopupWindow(final boolean drop) {
+ _displayHidePopupWindow(false);
+ }
+
+ /**
+ * _display hide popup window.
+ *
+ * @param show the show
+ */
+ private void _displayHidePopupWindow(final boolean show) {
+ if (show == isPopupVisible()) {
+ return;
+ }
+
+ if (!show) {
+ this.popup.setVisible(false);
+ if (!isDisposed()) {
+ this.label.setFocus();
+ }
+ return;
+ }
+
+ if (getShell() != this.popup.getParent()) {
+ this.popup.dispose();
+ this.popup = null;
+ createPopupShell();
+ }
+
+ final Point textRect = this.label.toDisplay(this.label.getLocation().x, this.label.getLocation().y);
+ final int x = textRect.x;
+ final int y = textRect.y + this.label.getSize().y;
+
+ this.popup.setLocation(x, y);
+ this.popup.setVisible(true);
+ this.popup.setFocus();
+ }
+
+ /**
+ * Creates the popup shell.
+ */
+ private void createPopupShell() {
+ this.popup = new Shell(getShell(), SWT.NO_TRIM | SWT.ON_TOP);
+ this.popup.setLayout(new GridLayout());
+
+ final int[] popupEvents = { SWT.Close, SWT.Paint, SWT.Deactivate, SWT.Dispose };
+ for (final int popupEvent : popupEvents) {
+ this.popup.addListener(popupEvent, this.listener);
+ }
+
+ this.composite = new CalculatorButtonsComposite(this.popup, SWT.NONE);
+ this.composite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+ this.composite.setDisplayArea(this.label);
+ this.keyListener = this.composite.getKeyListener();
+ this.label.addKeyListener(this.keyListener);
+
+ this.popup.pack();
+ }
+
+ /**
+ * Handle button event.
+ *
+ * @param event the event
+ */
+ private void handleButtonEvent(final Event event) {
+ switch (event.type) {
+ case SWT.FocusIn: {
+ handleFocusEvent(SWT.FocusIn);
+ break;
+ }
+ case SWT.Selection: {
+ _displayHidePopupWindow(!isPopupVisible());
+ break;
+ }
+ }
+ }
+
+ /**
+ * Handle focus event.
+ *
+ * @param eventType the event type
+ */
+ private void handleFocusEvent(final int eventType) {
+ if (isDisposed()) {
+ return;
+ }
+ switch (eventType) {
+ case SWT.FocusIn: {
+ if (this.hasFocus) {
+ return;
+ }
+ this.hasFocus = true;
+ final Shell shell = getShell();
+ shell.removeListener(SWT.Deactivate, this.listener);
+ shell.addListener(SWT.Deactivate, this.listener);
+ final Display display = getDisplay();
+ display.removeFilter(SWT.FocusIn, this.filter);
+ display.addFilter(SWT.FocusIn, this.filter);
+ final Event e = new Event();
+ notifyListeners(SWT.FocusIn, e);
+ break;
+ }
+ case SWT.FocusOut: {
+ if (!this.hasFocus) {
+ return;
+ }
+ final Control focusControl = getDisplay().getFocusControl();
+ if (focusControl == this.arrow) {
+ return;
+ }
+ this.hasFocus = false;
+ final Shell shell = getShell();
+ shell.removeListener(SWT.Deactivate, this.listener);
+ final Display display = getDisplay();
+ display.removeFilter(SWT.FocusIn, this.filter);
+ final Event e = new Event();
+ notifyListeners(SWT.FocusOut, e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Checks if is popup visible.
+ *
+ * @return true, if is popup visible
+ */
+ private boolean isPopupVisible() {
+ return !this.popup.isDisposed() && this.popup.getVisible();
+ }
+
+ /**
+ * Handle multi choice event.
+ *
+ * @param event the event
+ */
+ private void handleMultiChoiceEvent(final Event event) {
+ switch (event.type) {
+ case SWT.Dispose:
+ if (this.popup != null && !this.popup.isDisposed()) {
+ this.popup.dispose();
+ }
+ final Shell shell = getShell();
+ shell.removeListener(SWT.Deactivate, this.listener);
+ final Display display = getDisplay();
+ display.removeFilter(SWT.FocusIn, this.filter);
+ this.popup = null;
+ this.arrow = null;
+ break;
+ case SWT.Move:
+ hidePopupWindow(false);
+ break;
+ case SWT.Resize:
+ if (isPopupVisible()) {
+ hidePopupWindow(false);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified
+ * when the receiver's text is modified, by sending it one of the messages
+ * defined in the <code>ModifyListener</code> interface.
+ *
+ * @param listener the listener which should be notified
+ * @see ModifyListener
+ * @see #removeModifyListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void addModifyListener(final ModifyListener listener) {
+ checkWidget();
+ this.composite.addModifyListener(listener);
+ }
+
+ /**
+ * Compute size.
+ *
+ * @param wHint the w hint
+ * @param hHint the h hint
+ * @param changed the changed
+ * @return the point
+ * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)
+ */
+ @Override
+ public Point computeSize(final int wHint, final int hHint, final boolean changed) {
+ checkWidget();
+ int width = 0, height = 0;
+
+ final GC gc = new GC(this.label);
+ final int spacer = gc.stringExtent(" ").x;
+ final int textWidth = gc.stringExtent(this.label.getText()).x;
+ gc.dispose();
+ final Point textSize = this.label.computeSize(SWT.DEFAULT, SWT.DEFAULT, changed);
+ final Point arrowSize = this.arrow.computeSize(SWT.DEFAULT, SWT.DEFAULT, changed);
+ final int borderWidth = getBorderWidth();
+
+ height = Math.max(textSize.y, arrowSize.y);
+ width = textWidth + 2 * spacer + arrowSize.x + 2 * borderWidth;
+ if (wHint != SWT.DEFAULT) {
+ width = wHint;
+ }
+ if (hHint != SWT.DEFAULT) {
+ height = hHint;
+ }
+ return new Point(width + 2 * borderWidth, height + 2 * borderWidth);
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value of the combo
+ */
+ public String getValue() {
+ checkWidget();
+ return this.label.getText();
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be
+ * notified when the receiver's text is modified.
+ *
+ * @param listener the listener which should no longer be notified
+ * @see ModifyListener
+ * @see #addModifyListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void removeModifyListener(final ModifyListener listener) {
+ checkWidget();
+ this.composite.removeModifyListener(listener);
+ }
+
+ /**
+ * Sets the enabled.
+ *
+ * @param enabled the new enabled
+ * @see org.eclipse.swt.widgets.Control#setEnabled(boolean)
+ */
+ @Override
+ public void setEnabled(final boolean enabled) {
+ checkWidget();
+ this.arrow.setEnabled(enabled);
+ this.label.setEnabled(enabled);
+ super.setEnabled(enabled);
+ }
+
+ /**
+ * Sets the tool tip text.
+ *
+ * @param txt the new tool tip text
+ * @see org.eclipse.swt.widgets.Control#setToolTipText(java.lang.String)
+ */
+ @Override
+ public void setToolTipText(final String txt) {
+ checkWidget();
+ this.label.setToolTipText(txt);
+ }
+
+ /**
+ * Sets the value.
+ *
+ * @param value new value
+ * @throws NumberFormatException if <code>value</code> is not a valid float
+ * value
+ */
+ public void setValue(final String value) {
+ checkWidget();
+ this.label.setText(value);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorEngine.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorEngine.java
new file mode 100644
index 0000000..fa960f6
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/CalculatorEngine.java
@@ -0,0 +1,355 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.calculator;
+
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * This is the calculator engine.
+ */
+class CalculatorEngine {
+
+ /** The Constant OPERATOR_PLUS. */
+ static final String OPERATOR_PLUS = "+";
+
+ /** The Constant OPERATOR_MINUS. */
+ static final String OPERATOR_MINUS = "-";
+
+ /** The Constant OPERATOR_MULTIPLY. */
+ static final String OPERATOR_MULTIPLY = "*";
+
+ /** The Constant OPERATOR_DIVIDE. */
+ static final String OPERATOR_DIVIDE = "/";
+
+ /** The Constant CHARACTER_ZERO. */
+ static final String CHARACTER_ZERO = "0";
+
+ /** The Constant DOT_CHARACTER. */
+ static final String DOT_CHARACTER = ".";
+
+ /** The Constant EMPTY_STRING. */
+ static final String EMPTY_STRING = "";
+
+ /**
+ * The Enum DISPLAY_MODE.
+ */
+ private enum DISPLAY_MODE {
+
+ /** The input. */
+ INPUT,
+ /** The result. */
+ RESULT,
+ /** The error. */
+ ERROR
+ }
+
+ /** The display mode. */
+ private DISPLAY_MODE displayMode;
+
+ /** The clear on next digit. */
+ private boolean clearOnNextDigit;
+
+ /** The last number. */
+ private double lastNumber;
+
+ /** The last operator. */
+ private String lastOperator;
+
+ /** The composite. */
+ private final CalculatorButtonsComposite composite;
+
+ /**
+ * Constructor.
+ *
+ * @param composite the composite
+ */
+ CalculatorEngine(final CalculatorButtonsComposite composite) {
+ this.composite = composite;
+ }
+
+ /**
+ * Add a decimal point.
+ */
+ void addDecimalPoint() {
+ this.displayMode = DISPLAY_MODE.INPUT;
+
+ if (this.clearOnNextDigit) {
+ setDisplayString(EMPTY_STRING);
+ }
+
+ final String inputString = getDisplayString();
+
+ if (inputString.indexOf(DOT_CHARACTER) < 0) {
+ setDisplayString(inputString + DOT_CHARACTER);
+ }
+ }
+
+ /**
+ * Sets the display string.
+ *
+ * @param value value to display
+ */
+ private void setDisplayString(final String value) {
+ this.composite.getDisplayArea().setText(value);
+ this.composite.fireModifyListeners();
+ }
+
+ /**
+ * Adds the digit to display.
+ *
+ * @param digit digit to add
+ */
+ void addDigitToDisplay(final int digit) {
+ if (this.clearOnNextDigit) {
+ setDisplayString(EMPTY_STRING);
+ }
+
+ String inputString = getDisplayString();
+
+ if (inputString.indexOf(CHARACTER_ZERO) == 0) {
+ inputString = inputString.substring(1);
+ }
+
+ if (!inputString.equals(CHARACTER_ZERO) || digit > 0) {
+ setDisplayString(inputString + digit);
+ }
+
+ this.displayMode = DISPLAY_MODE.INPUT;
+ this.clearOnNextDigit = false;
+ }
+
+ /**
+ * Clear content.
+ */
+ void clearWholeContent() {
+ setDisplayString(CHARACTER_ZERO);
+ this.lastOperator = CHARACTER_ZERO;
+ this.lastNumber = 0;
+ this.displayMode = DISPLAY_MODE.INPUT;
+ this.clearOnNextDigit = true;
+ }
+
+ /**
+ * Clear result.
+ */
+ void clearResult() {
+ setDisplayString(CHARACTER_ZERO);
+ this.clearOnNextDigit = true;
+ this.displayMode = DISPLAY_MODE.INPUT;
+ }
+
+ /**
+ * Process backspace.
+ */
+ void processBackSpace() {
+ if (this.displayMode != DISPLAY_MODE.ERROR) {
+ setDisplayString(getDisplayString().substring(0, getDisplayString().length() - 1));
+ if (getDisplayString().length() < 1) {
+ setDisplayString(CHARACTER_ZERO);
+ }
+ }
+ }
+
+ /**
+ * Gets the display string.
+ *
+ * @return the displayed value as string
+ */
+ private String getDisplayString() {
+ return this.composite.getDisplayArea().getText();
+ }
+
+ /**
+ * Process equals operation.
+ */
+ void processEquals() {
+ double result = 0;
+
+ if (this.displayMode != DISPLAY_MODE.ERROR) {
+ try {
+ result = processLastOperator();
+ displayResult(result);
+ } catch (final DivideByZeroException e) { // NOSONAR
+ displayErrorMessage(ResourceManager.CALCULATOR_DIVIDE_BY_ZERO);
+ }
+ this.lastOperator = CHARACTER_ZERO;
+ }
+ }
+
+ /**
+ * Process last operator.
+ *
+ * @return the result of the last operation
+ * @throws DivideByZeroException the divide by zero exception
+ */
+ private double processLastOperator() throws DivideByZeroException {
+ double result = 0;
+ final double numberInDisplay = getDisplayedNumber();
+
+ if (this.lastOperator.equals(OPERATOR_DIVIDE)) {
+ if ( Double.compare( numberInDisplay, (double) 0.0 ) == 0 ) {
+ throw new DivideByZeroException();
+ }
+ result = this.lastNumber / numberInDisplay;
+ }
+
+ if (this.lastOperator.equals(OPERATOR_MULTIPLY)) {
+ result = this.lastNumber * numberInDisplay;
+ }
+
+ if (this.lastOperator.equals(OPERATOR_MINUS)) {
+ result = this.lastNumber - numberInDisplay;
+ }
+
+ if (this.lastOperator.equals(OPERATOR_PLUS)) {
+ result = this.lastNumber + numberInDisplay;
+ }
+
+ return result;
+ }
+
+ /**
+ * Display result.
+ *
+ * @param result result to display
+ */
+ private void displayResult(final double result) {
+ if ( Double.compare( Math.floor(result), result ) == 0 ) {
+ setDisplayString(Integer.toString((int) result));
+ } else {
+ setDisplayString(Double.toString(result));
+ }
+ this.lastNumber = result;
+ this.displayMode = DISPLAY_MODE.RESULT;
+ this.clearOnNextDigit = true;
+ }
+
+ /**
+ * Display error message.
+ *
+ * @param errorMessage error message
+ */
+ private void displayErrorMessage(final String errorMessage) {
+ setDisplayString(ResourceManager.getLabel(errorMessage));
+ this.lastNumber = 0;
+ this.displayMode = DISPLAY_MODE.ERROR;
+ this.clearOnNextDigit = true;
+ }
+
+ /**
+ * Process 1/x operation.
+ */
+ void processInverseOperation() {
+ if (this.displayMode != DISPLAY_MODE.ERROR) {
+ try {
+ if ( Double.compare( getDisplayedNumber(), (double) 0.0 ) == 0 ) {
+ displayErrorMessage(ResourceManager.CALCULATOR_DIVIDE_BY_ZERO);
+ return;
+ }
+ final double result = 1 / getDisplayedNumber();
+ displayResult(result);
+ } catch (final Exception ex) { // NOSONAR
+ displayErrorMessage(ResourceManager.CALCULATOR_DIVIDE_BY_ZERO);
+ this.displayMode = DISPLAY_MODE.ERROR;
+ }
+ }
+ }
+
+ /**
+ * Gets the displayed number.
+ *
+ * @return the displayed number
+ */
+ private double getDisplayedNumber() {
+ final String input = getDisplayString();
+ return Double.parseDouble(input);
+ }
+
+ /**
+ * Process operation.
+ *
+ * @param operator operation to process
+ */
+ void processOperation(final String operator) {
+ if (this.displayMode != DISPLAY_MODE.ERROR) {
+ final double numberInDisplay = getDisplayedNumber();
+ if (this.lastOperator != null && !this.lastOperator.equals(CHARACTER_ZERO)) {
+ try {
+ final double result = processLastOperator();
+ displayResult(result);
+ this.lastNumber = result;
+ } catch (final DivideByZeroException e) { // NOSONAR
+ }
+ } else {
+ this.lastNumber = numberInDisplay;
+ }
+ this.clearOnNextDigit = true;
+ this.lastOperator = operator;
+ }
+ }
+
+ /**
+ * Process percentage operation.
+ */
+ void processPerCentageOperation() {
+ if (this.displayMode != DISPLAY_MODE.ERROR) {
+ try {
+ final double result = getDisplayedNumber() / 100;
+ displayResult(result);
+ } catch (final Exception ex) { // NOSONAR
+ displayErrorMessage(ResourceManager.CALCULATOR_INVALID_VALUE);
+ this.displayMode = DISPLAY_MODE.ERROR;
+ }
+ }
+ }
+
+ /**
+ * Process +/- operation.
+ */
+ void processSignChange() {
+ if (this.displayMode == DISPLAY_MODE.INPUT) {
+ final String input = getDisplayString();
+ if (input.length() > 0 && !input.equals(CHARACTER_ZERO)) {
+ if (input.indexOf(OPERATOR_MINUS) == 0) {
+ setDisplayString(input.substring(1));
+ } else {
+ setDisplayString(OPERATOR_MINUS + input);
+ }
+ }
+ } else if (this.displayMode == DISPLAY_MODE.RESULT) {
+ final double numberInDisplay = getDisplayedNumber();
+
+ if ( Double.compare( numberInDisplay, (double) 0.0 ) != 0 ) {
+ displayResult( -numberInDisplay );
+ }
+ }
+ }
+
+ /**
+ * Process square root operation.
+ */
+ void processSquareRootOperation() {
+ if (this.displayMode != DISPLAY_MODE.ERROR) {
+ try {
+ if (getDisplayString().indexOf(OPERATOR_MINUS) == 0) {
+ displayErrorMessage(ResourceManager.CALCULATOR_INVALID_VALUE);
+ }
+
+ final double result = Math.sqrt(getDisplayedNumber());
+ displayResult(result);
+ } catch (final Exception ex) { // NOSONAR
+ displayErrorMessage(ResourceManager.CALCULATOR_INVALID_VALUE);
+ this.displayMode = DISPLAY_MODE.ERROR;
+ }
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/DivideByZeroException.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/DivideByZeroException.java
new file mode 100644
index 0000000..538f9d9
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/calculator/DivideByZeroException.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.calculator;
+
+/**
+ * The Class DivideByZeroException.
+ */
+class DivideByZeroException extends Exception {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 1764265506499117961L;
+
+ /**
+ * Constructor.
+ */
+ public DivideByZeroException() {
+ super();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param errorMessage error message
+ */
+ public DivideByZeroException(final String errorMessage) {
+ super(errorMessage);
+ }
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/checkBoxGroup/CheckBoxGroup.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/checkBoxGroup/CheckBoxGroup.java
new file mode 100644
index 0000000..811d05b
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/checkBoxGroup/CheckBoxGroup.java
@@ -0,0 +1,360 @@
+/*******************************************************************************
+ * Copyright (c) 2011,2012 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial implementation and API
+ * Marnix van Bochove (mgvanbochove at gmail dot com) - Enhancements and bug fixes
+ *******************************************************************************/
+package org.mihalis.opal.checkBoxGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Widget;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class provide an etched border with a title and a checkbox. If the checkbox is checked, the content of the composite is enabled. If the checkbox is unchecked, the content of the composite is disabled, thus not editable.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ */
+public class CheckBoxGroup extends Canvas implements PaintListener {
+
+ /** The button. */
+ protected Button button;
+
+ /** The content. */
+ private final Composite content;
+
+ /** The selection listeners. */
+ private final List<SelectionListener> selectionListeners;
+
+ /** The transparent. */
+ private boolean transparent = false;
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance
+ * (cannot be null)
+ * @param style the style of widget to construct
+ * @see Composite#Composite(Composite, int)
+ * @see SWT#BORDER
+ * @see Widget#getStyle
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ public CheckBoxGroup(final Composite parent, final int style) {
+ super(parent, style);
+ super.setLayout(new GridLayout());
+
+ this.selectionListeners = new ArrayList<SelectionListener>();
+
+ createCheckBoxButton();
+
+ this.content = new Composite(this, style);
+ this.content.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+
+ this.addPaintListener(this);
+ }
+
+ /**
+ * Creates the check box button.
+ */
+ private void createCheckBoxButton() {
+ this.button = new Button(this, SWT.CHECK);
+ final GridData gdButton = new GridData(GridData.BEGINNING, GridData.CENTER, true, false);
+ gdButton.horizontalIndent = 15;
+ this.button.setLayoutData(gdButton);
+ this.button.setSelection(true);
+ this.button.pack();
+
+ this.button.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ e.doit = fireSelectionListeners(e);
+ if (!e.doit) {
+ return;
+ }
+ if (CheckBoxGroup.this.button.getSelection()) {
+ CheckBoxGroup.this.activate();
+ } else {
+ CheckBoxGroup.this.deactivate();
+ }
+ }
+ });
+ }
+
+ /**
+ * Fire the selection listeners.
+ *
+ * @param selectionEvent mouse event
+ * @return true if the selection could be changed, false otherwise
+ */
+ private boolean fireSelectionListeners(final SelectionEvent selectionEvent) {
+ selectionEvent.widget = this;
+ for (final SelectionListener listener : this.selectionListeners) {
+ listener.widgetSelected(selectionEvent);
+ if (!selectionEvent.doit) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Activate the content.
+ */
+ public void activate() {
+ this.button.setSelection(true);
+ SWTGraphicUtil.enableAllChildrenWidgets(this.content);
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified
+ * when the user changes the receiver's selection, by sending it one of the
+ * messages defined in the <code>SelectionListener</code> interface.
+ * <p>
+ * When <code>widgetSelected</code> is called, the item field of the event
+ * object is valid. If the receiver has the <code>SWT.CHECK</code> style and
+ * the check selection changes, the event object detail field contains the
+ * value <code>SWT.CHECK</code>. <code>widgetDefaultSelected</code> is
+ * typically called when an item is double-clicked. The item field of the
+ * event object is valid for default selection, but the detail field is not
+ * used.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the user
+ * changes the receiver's selection
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void addSelectionListener(final SelectionListener listener) {
+ checkWidget();
+ this.selectionListeners.add(listener);
+ }
+
+ /**
+ * Deactivate the content.
+ */
+ public void deactivate() {
+ this.button.setSelection(false);
+ SWTGraphicUtil.disableAllChildrenWidgets(this.content);
+ }
+
+ /**
+ * Checks if is activated.
+ *
+ * @return <code>true</code> if the content is activated, <code>false</code>
+ * otherwise
+ */
+ public boolean isActivated() {
+ return this.button.getSelection();
+ }
+
+ /**
+ * Gets the layout.
+ *
+ * @return the layout
+ * @see org.eclipse.swt.widgets.Composite#getLayout()
+ */
+ @Override
+ public Layout getLayout() {
+ return this.content.getLayout();
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be
+ * notified when the user changes the receiver's selection.
+ *
+ * @param listener the listener which should no longer be notified
+ * @see SelectionListener
+ * @see #addSelectionListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void removeSelectionListener(final SelectionListener listener) {
+ checkWidget();
+ this.selectionListeners.remove(listener);
+ }
+
+ /**
+ * Sets the focus.
+ *
+ * @return true, if successful
+ * @see org.eclipse.swt.widgets.Composite#setFocus()
+ */
+ @Override
+ public boolean setFocus() {
+ return this.content.setFocus();
+ }
+
+ /**
+ * Sets the layout.
+ *
+ * @param layout the new layout
+ * @see org.eclipse.swt.widgets.Composite#setLayout(org.eclipse.swt.widgets.Layout)
+ */
+ @Override
+ public void setLayout(final Layout layout) {
+ this.content.setLayout(layout);
+ }
+
+ // ------------------------------------ Getters and Setters
+
+ /**
+ * Gets the text.
+ *
+ * @return the text of the button
+ */
+ public String getText() {
+ return this.button.getText();
+ }
+
+ /**
+ * Sets the text.
+ *
+ * @param text the text of the button to set
+ */
+ public void setText(final String text) {
+ this.button.setText(text);
+ }
+
+ /**
+ * Gets the font.
+ *
+ * @return the font of the button
+ */
+ @Override
+ public Font getFont() {
+ return this.button.getFont();
+ }
+
+ /**
+ * Sets the font.
+ *
+ * @param font the font to set
+ */
+ @Override
+ public void setFont(final Font font) {
+ this.button.setFont(font);
+ }
+
+ /**
+ * Gets the content.
+ *
+ * @return the content of the group
+ */
+ public Composite getContent() {
+ return this.content;
+ }
+
+ /**
+ * Checks if is transparent.
+ *
+ * @return true, if is transparent
+ */
+ public boolean isTransparent() {
+ return this.transparent;
+ }
+
+ /**
+ * Sets the transparent.
+ *
+ * @param transparent the new transparent
+ */
+ public void setTransparent(final boolean transparent) {
+ this.transparent = transparent;
+ if (transparent) {
+ setBackgroundMode(SWT.INHERIT_DEFAULT);
+ this.content.setBackgroundMode(SWT.INHERIT_DEFAULT);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)
+ */
+ @Override
+ public void paintControl(final PaintEvent paintEvent) {
+ if (paintEvent.widget == this) {
+ drawWidget(paintEvent.gc);
+ }
+ }
+
+ /**
+ * Draws the widget.
+ *
+ * @param gc the gc
+ */
+ private void drawWidget(final GC gc) {
+ final Rectangle rect = this.getClientArea();
+ final int margin = (int) (this.button.getSize().y * 1.5);
+ final int startY = margin / 2;
+
+ gc.setForeground(this.getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
+ gc.drawRoundRectangle(1, startY, rect.width - 2, rect.height - startY - 2, 2, 2);
+
+ gc.setForeground(this.getDisplay().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW));
+ gc.drawRoundRectangle(2, startY + 1, rect.width - 4, rect.height - startY - 4, 2, 2);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/columns/ColumnBrowserWidget.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/columns/ColumnBrowserWidget.java
new file mode 100644
index 0000000..ae47940
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/columns/ColumnBrowserWidget.java
@@ -0,0 +1,771 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial implementation and API
+ *******************************************************************************/
+package org.mihalis.opal.columns;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Widget;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class provide a data browser similar to the ones used in
+ * Mac OS X. Look at http://en.wikipedia.org/wiki/Miller_Columns
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ */
+public class ColumnBrowserWidget extends ScrolledComposite {
+
+ /** The columns. */
+ private final List<Table> columns;
+
+ /** The composite. */
+ private final Composite composite;
+
+ /** The column arrow. */
+ private final Image columnArrow;
+
+ /** The selection listeners. */
+ private final List<SelectionListener> selectionListeners;
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance
+ * (cannot be null)
+ * @param style the style of widget to construct
+ * @see Composite#Composite(Composite, int)
+ * @see SWT#BORDER
+ * @see Widget#getStyle
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ public ColumnBrowserWidget(final Composite parent, final int style) {
+ super(parent, style | SWT.H_SCROLL | SWT.V_SCROLL);
+
+ this.composite = new Composite(this, SWT.NONE);
+ final RowLayout layout = new RowLayout(SWT.HORIZONTAL);
+ layout.spacing = 1;
+ layout.pack = false;
+ this.composite.setLayout(layout);
+
+ this.columnArrow = SWTGraphicUtil.createImageFromFile("images/columnArrow.png");
+
+ this.columns = new ArrayList<Table>();
+ for (int i = 0; i < 3; i++) {
+ this.createTable();
+ }
+
+ // Store root
+ this.columns.get(0).setData(new ColumnItem(this));
+
+ this.setContent(this.composite);
+ this.setExpandHorizontal(true);
+ this.setExpandVertical(true);
+ this.setShowFocusedControl(true);
+ this.updateContent();
+ this.setMinSize(this.composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+
+ this.selectionListeners = new ArrayList<SelectionListener>();
+
+ this.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent arg0) {
+ SWTGraphicUtil.safeDispose(ColumnBrowserWidget.this.columnArrow);
+ }
+ });
+
+ }
+
+ /**
+ * Create a column that displays data.
+ */
+ private void createTable() {
+ final Table table = new Table(this.composite, SWT.SINGLE | SWT.H_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
+
+ table.setLayoutData(new RowData(150, 175));
+ this.columns.add(table);
+
+ addTableListeners(table);
+
+ if (super.getBackground() != null && super.getBackground().getRed() != 240 && super.getBackground().getGreen() != 240 && super.getBackground().getBlue() != 240) {
+ table.setBackground(super.getBackground());
+ }
+ table.setBackgroundImage(super.getBackgroundImage());
+ table.setBackgroundMode(super.getBackgroundMode());
+ table.setCursor(super.getCursor());
+ table.setFont(super.getFont());
+ table.setForeground(super.getForeground());
+ table.setMenu(super.getMenu());
+ table.setToolTipText(super.getToolTipText());
+
+ }
+
+ /**
+ * Adds the table listeners.
+ *
+ * @param table the table
+ */
+ private void addTableListeners(final Table table) {
+ table.addListener(SWT.Resize, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ final int width = table.getSize().x;
+ table.getColumn(0).setWidth(width - 5);
+ }
+ });
+
+ table.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ final Table table = (Table) event.widget;
+ if (table.getSelection() == null || table.getSelection().length != 1) {
+ return;
+ }
+ ColumnBrowserWidget.this.selectItem(table.getSelection()[0]);
+ }
+ });
+
+ final Listener paintListener = new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ switch (event.type) {
+ case SWT.MeasureItem: {
+ final Rectangle rect = ColumnBrowserWidget.this.columnArrow.getBounds();
+ event.width += rect.width;
+ event.height = Math.max(event.height, rect.height + 2);
+ break;
+ }
+
+ case SWT.PaintItem: {
+ if (!(event.item instanceof TableItem)) {
+ return;
+ }
+ final TableItem item = (TableItem) event.item;
+ if (item.getData() == null) {
+ return;
+ }
+
+ if (((ColumnItem) item.getData()).getItemCount() == 0) {
+ return;
+ }
+
+ final int x = event.x + event.width;
+ final Rectangle rect = ColumnBrowserWidget.this.columnArrow.getBounds();
+ final int offset = Math.max(0, (event.height - rect.height) / 2);
+ event.gc.drawImage(ColumnBrowserWidget.this.columnArrow, x, event.y + offset);
+ break;
+ }
+ }
+ }
+ };
+ table.addListener(SWT.MeasureItem, paintListener);
+ table.addListener(SWT.PaintItem, paintListener);
+
+ table.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ ColumnBrowserWidget.this.fireSelectionListeners(e);
+ }
+
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ ColumnBrowserWidget.this.fireSelectionListeners(e);
+ }
+ });
+ }
+
+ /**
+ * Fire the selection listeners.
+ *
+ * @param selectionEvent mouse event
+ * @return true if the selection could be changed, false otherwise
+ */
+ private boolean fireSelectionListeners(final SelectionEvent selectionEvent) {
+ final Event event = new Event();
+
+ event.button = 0;
+ event.display = this.getDisplay();
+ event.item = null;
+ event.widget = this;
+ event.data = null;
+ event.time = selectionEvent.time;
+ event.x = selectionEvent.x;
+ event.y = selectionEvent.y;
+
+ final SelectionEvent selEvent = new SelectionEvent(event);
+
+ for (final SelectionListener listener : this.selectionListeners) {
+ listener.widgetSelected(selEvent);
+ if (!selEvent.doit) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Perform actions when an item is selected (ie fill the next column and
+ * force focus on it).
+ *
+ * @param tableItem selected item
+ */
+ private void selectItem(final TableItem tableItem) {
+ final ColumnItem c = (ColumnItem) tableItem.getData();
+
+ if (c.getItemCount() == 0) {
+ return;
+ }
+
+ final int selectedColumn = this.findSelectedColumn(tableItem);
+ boolean needPacking = false;
+ if (selectedColumn != this.columns.size() - 1) {
+ for (int i = selectedColumn + 1; i < this.columns.size(); i++) {
+ this.columns.get(i).setData(null);
+ this.columns.get(i).deselectAll();
+ }
+
+ int i = 0;
+ final Iterator<Table> it = this.columns.iterator();
+ while (it.hasNext()) {
+ final Table t = it.next();
+ if (i > selectedColumn) {
+ t.dispose();
+ it.remove();
+ this.setMinSize(this.composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ }
+ i++;
+ }
+
+ if (selectedColumn != this.columns.size() - 1) {
+ this.columns.get(selectedColumn + 1).setData(c);
+ } else {
+ this.createTable();
+ this.columns.get(this.columns.size() - 1).setData(c);
+ }
+ needPacking = true;
+
+ } else {
+ this.createTable();
+ needPacking = true;
+ this.columns.get(this.columns.size() - 1).setData(c);
+ }
+ this.updateContent();
+ if (needPacking) { // NOSONAR
+ this.composite.pack();
+ this.setMinSize(this.composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ }
+ this.columns.get(this.columns.size() - 1).forceFocus();
+ }
+
+ /**
+ * Find which column has been selected.
+ *
+ * @param tableItem selected table item
+ * @return the index of the selected column
+ */
+ private int findSelectedColumn(final TableItem tableItem) {
+ for (int i = 0; i < this.columns.size(); i++) {
+ if (this.columns.get(i).equals(tableItem.getParent())) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Update the content of the widget.
+ */
+ void updateContent() {
+ if (this.columns == null) {
+ return;
+ }
+
+ for (int i = 0; i < this.columns.size(); i++) {
+
+ final Table table = this.columns.get(i);
+ final int index = table.getSelectionIndex();
+ table.removeAll();
+ if (table.getData() == null) {
+ continue;
+ }
+ for (final ColumnItem c : ((ColumnItem) table.getData()).getItems()) {
+ final TableItem item = new TableItem(table, SWT.NONE);
+ item.setData(c);
+ if (c.getText() != null) {
+ item.setText(c.getText());
+ }
+ if (c.getImage() != null) {
+ item.setImage(c.getImage());
+ }
+ }
+ table.setSelection(index);
+ }
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified
+ * when the user changes the receiver's selection, by sending it one of the
+ * messages defined in the <code>SelectionListener</code> interface.
+ *
+ * @param listener the listener which should be notified when the user
+ * changes the receiver's selection
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void addSelectionListener(final SelectionListener listener) {
+ checkWidget();
+ this.selectionListeners.add(listener);
+ }
+
+ /**
+ * Clear the selection.
+ *
+ * @param needPacking if <code>true</code>, the widget is packed
+ */
+ public void clear(final boolean needPacking) {
+ final Iterator<Table> it = this.columns.iterator();
+ int i = 0;
+ while (it.hasNext()) {
+ final Table t = it.next();
+ if (i >= 3) {
+ t.dispose();
+ it.remove();
+ } else {
+ if (i != 0) {
+ t.setData(null);
+ }
+ t.deselectAll();
+ }
+ i++;
+ }
+ this.updateContent();
+ if (needPacking) {
+ this.composite.pack();
+ this.setMinSize(this.composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ }
+ this.columns.get(0).forceFocus();
+ }
+
+ /**
+ * Returns the <code>ColumnItem</code>s that is currently selected in the
+ * receiver.
+ *
+ * @return the selected item, or <code>null</code> if no one is selected
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public ColumnItem getSelection() {
+ for (int i = this.columns.size() - 1; i >= 0; i--) {
+ final Table table = this.columns.get(i);
+ if (table == null || table.getData() == null || table.getSelection().length == 0) {
+ continue;
+ }
+ return (ColumnItem) table.getItem(table.getSelectionIndex()).getData();
+ }
+ return null;
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be
+ * notified when the user changes the receiver's selection.
+ *
+ * @param listener the listener which should no longer be notified
+ * @see SelectionListener
+ * @see #addSelectionListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void removeSelectionListener(final SelectionListener listener) {
+ checkWidget();
+ this.selectionListeners.remove(listener);
+ }
+
+ /**
+ * Selects an item in the receiver. If the item was already selected, it
+ * remains selected.
+ *
+ * @param item the item to be selected
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed
+ * </li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void select(final ColumnItem item) {
+
+ final List<ColumnItem> items = new ArrayList<ColumnItem>();
+ this.findElement(item, items);
+ Collections.reverse(items);
+ if (items.isEmpty()) {
+ return;
+ }
+
+ this.clear(false);
+ for (int i = 3; i < items.size(); i++) {
+ this.createTable();
+ }
+ for (int i = 0; i < items.size() - 1; i++) {
+ this.columns.get(i + 1).setData(items.get(i));
+ }
+ this.updateContent();
+
+ for (int i = 0; i < this.columns.size() - 1; i++) {
+ final ColumnItem nextItem = (ColumnItem) this.columns.get(i + 1).getData();
+ for (final TableItem tableItem : this.columns.get(i).getItems()) {
+ if (tableItem.getData() != null && tableItem.getData().equals(nextItem)) {
+ tableItem.getParent().setSelection(tableItem);
+ }
+ }
+ }
+
+ this.composite.pack();
+ this.setMinSize(this.composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ this.columns.get(this.columns.size() - 1).forceFocus();
+
+ }
+
+ /**
+ * Build an array that contains the hierarchy of ColumnItem from the root
+ * node to a given item.
+ *
+ * @param item item to find
+ * @param items the lists of item that composes the hierarchy
+ */
+ private void findElement(final ColumnItem item, final List<ColumnItem> items) {
+ if (item == null) {
+ return;
+ }
+ items.add(item);
+ this.findElement(item.getParentItem(), items);
+ }
+
+ /**
+ * Sets the receiver's background color to the color specified by the
+ * argument, or to the default system color for the control if the argument
+ * is null.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform. For
+ * example, on Windows the background of a Button cannot be changed.
+ * </p>
+ *
+ * @param color the new color (or null)
+ * @see org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics.Color)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setBackground(final Color color) {
+ super.setBackground(color);
+ for (final Table column : this.columns) {
+ column.setBackground(color);
+ }
+ }
+
+ /**
+ * Sets the background drawing mode to the argument which should be one of
+ * the following constants defined in class <code>SWT</code>:
+ * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>,
+ * <code>INHERIT_FORCE</code>.
+ *
+ * @param mode the new background mode
+ * @see SWT
+ * @see org.eclipse.swt.widgets.Composite#setBackgroundMode(int)
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setBackgroundMode(final int mode) {
+ super.setBackgroundMode(mode);
+ for (final Table column : this.columns) {
+ column.setBackgroundMode(mode);
+ }
+ }
+
+ /**
+ * Sets the receiver's background image to the image specified by the
+ * argument, or to the default system color for the control if the argument
+ * is null. The background image is tiled to fill the available space.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform. For
+ * example, on Windows the background of a Button cannot be changed.
+ * </p>
+ *
+ * @param image the new image (or null)
+ * @see org.eclipse.swt.widgets.Control#setBackgroundImage(org.eclipse.swt.graphics.Image)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument is not a
+ * bitmap</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setBackgroundImage(final Image image) {
+ super.setBackgroundImage(image);
+ for (final Table column : this.columns) {
+ column.setBackgroundImage(image);
+ }
+ }
+
+ /**
+ * Sets the receiver's cursor to the cursor specified by the argument, or to
+ * the default cursor for that kind of control if the argument is null.
+ * <p>
+ * When the mouse pointer passes over a control its appearance is changed to
+ * match the control's cursor.
+ * </p>
+ *
+ * @param cursor the new cursor (or null)
+ * @see org.eclipse.swt.widgets.Control#setCursor(org.eclipse.swt.graphics.Cursor)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setCursor(final Cursor cursor) {
+ super.setCursor(cursor);
+ for (final Table column : this.columns) {
+ column.setCursor(cursor);
+ }
+ }
+
+ /**
+ * Sets the font that the receiver will use to paint textual information to
+ * the font specified by the argument, or to the default font for that kind
+ * of control if the argument is null.
+ *
+ * @param font the new font (or null)
+ * @see org.eclipse.swt.widgets.Control#setFont(org.eclipse.swt.graphics.Font)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setFont(final Font font) {
+ super.setFont(font);
+ for (final Table column : this.columns) {
+ column.setFont(font);
+ }
+ }
+
+ /**
+ * Sets the receiver's foreground color to the color specified by the
+ * argument, or to the default system color for the control if the argument
+ * is null.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform.
+ * </p>
+ *
+ * @param color the new color (or null)
+ * @see org.eclipse.swt.widgets.Control#setForeground(org.eclipse.swt.graphics.Color)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setForeground(final Color color) {
+ super.setForeground(color);
+ for (final Table column : this.columns) {
+ column.setForeground(color);
+ }
+ }
+
+ /**
+ * Sets the receiver's pop up menu to the argument. All controls may
+ * optionally have a pop up menu that is displayed when the user requests
+ * one for the control. The sequence of key strokes, button presses and/or
+ * button releases that are used to request a pop up menu is platform
+ * specific.
+ * <p>
+ * Note: Disposing of a control that has a pop up menu will dispose of the
+ * menu. To avoid this behavior, set the menu to null before the control is
+ * disposed.
+ * </p>
+ *
+ * @param menu the new pop up menu
+ * @see org.eclipse.swt.widgets.Control#setMenu(org.eclipse.swt.widgets.Menu)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_MENU_NOT_POP_UP - the menu is not a pop up menu</li>
+ * <li>ERROR_INVALID_PARENT - if the menu is not in the same
+ * widget tree</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the menu has been disposed
+ * </li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setMenu(final Menu menu) {
+ super.setMenu(menu);
+ for (final Table column : this.columns) {
+ column.setMenu(menu);
+ }
+ }
+
+ /**
+ * Sets the receiver's tool tip text to the argument, which may be null
+ * indicating that the default tool tip for the control will be shown. For a
+ * control that has a default tool tip, such as the Tree control on Windows,
+ * setting the tool tip text to an empty string replaces the default,
+ * causing no tool tip text to be shown.
+ * <p>
+ * The mnemonic indicator (character '&amp;') is not displayed in a tool
+ * tip. To display a single '&amp;' in the tool tip, the character '&amp;'
+ * can be escaped by doubling it in the string.
+ * </p>
+ *
+ * @param tooltipText the new tool tip text
+ * @see org.eclipse.swt.widgets.Control#setToolTipText(java.lang.String)
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setToolTipText(final String tooltipText) {
+ super.setToolTipText(tooltipText);
+ for (final Table column : this.columns) {
+ column.setToolTipText(tooltipText);
+ }
+ }
+
+ /**
+ * Gets the root item.
+ *
+ * @return the root item, or null if there is no data
+ */
+ ColumnItem getRootItem() {
+ if (this.columns == null || this.columns.isEmpty()) {
+ return null;
+ }
+ return (ColumnItem) this.columns.get(0).getData();
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/columns/ColumnItem.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/columns/ColumnItem.java
new file mode 100644
index 0000000..8372c73
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/columns/ColumnItem.java
@@ -0,0 +1,426 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial implementation and API
+ *******************************************************************************/
+package org.mihalis.opal.columns;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.mihalis.opal.OpalItem;
+
+/**
+ * Instances of this object are items manipulated by the ColumnBrowser widget.
+ * ColumnItems are part of a tree structure .
+ *
+ * @see OpalItem
+ */
+public class ColumnItem extends OpalItem {
+
+ /** The widget. */
+ private final ColumnBrowserWidget widget;
+
+ /** The parent. */
+ private final ColumnItem parent;
+
+ /** The children. */
+ private final List<ColumnItem> children;
+
+ /**
+ * Constructs a new instance of this class given its parent. The item is
+ * added to the end of the items maintained by its parent.
+ *
+ * @param widget the widget that will contain this item (can not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public ColumnItem(final ColumnBrowserWidget widget) {
+ if (widget == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ this.widget = widget;
+ this.parent = null;
+ this.children = new ArrayList<ColumnItem>();
+
+ if (widget.getRootItem() != null) {
+ widget.getRootItem().children.add(this);
+ }
+ widget.updateContent();
+ }
+
+ /**
+ * Constructs a new instance of this class given its parent. The item is
+ * added at a given position in the items'list maintained by its parent.
+ *
+ * @param widget the widget that will contain this item (can not be null)
+ * @param index the position
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public ColumnItem(final ColumnBrowserWidget widget, final int index) {
+
+ if (widget == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ this.widget = widget;
+ this.parent = null;
+ this.children = new ArrayList<ColumnItem>();
+ widget.getRootItem().children.add(index, this);
+ widget.updateContent();
+ }
+
+ /**
+ * Constructs a new instance of this class given its parent. The item is
+ * added to the end of the items maintained by its parent.
+ *
+ * @param parent the parent
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public ColumnItem(final ColumnItem parent) {
+
+ if (parent == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (parent.widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ this.widget = parent.widget;
+ this.parent = parent;
+ this.children = new ArrayList<ColumnItem>();
+ parent.children.add(this);
+ parent.widget.updateContent();
+ }
+
+ /**
+ * Constructs a new instance of this class given its parent. The item is
+ * added at a given position in the items'list maintained by its parent.
+ *
+ * @param parent the parent
+ * @param index the position
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public ColumnItem(final ColumnItem parent, final int index) {
+ if (parent == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (parent.widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ this.widget = parent.widget;
+ this.parent = parent;
+ this.children = new ArrayList<ColumnItem>();
+ parent.children.add(index, this);
+ parent.widget.updateContent();
+ }
+
+ /**
+ * Remove a given children of this object.
+ *
+ * @param item the item to remove (can not be null)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public void remove(final ColumnItem item) {
+ if (this.widget == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (this.widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+ this.children.remove(item);
+ this.widget.updateContent();
+ }
+
+ /**
+ * Remove a children in a given position of this object.
+ *
+ * @param index position of the children in the items'list
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public void remove(final int index) {
+ if (this.widget == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (this.widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+ this.children.remove(index);
+ this.widget.updateContent();
+ }
+
+ /**
+ * Remove all children of this object.
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public void removeAll() {
+ if (this.widget == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (this.widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+ this.children.clear();
+ this.widget.updateContent();
+ }
+
+ /**
+ * Returns an item located at a given position.
+ *
+ * @param index position
+ * @return the item located at the index position
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public ColumnItem getItem(final int index) {
+ if (this.widget == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (this.widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+ return this.children.get(index);
+ }
+
+ /**
+ * Gets the item count.
+ *
+ * @return the number of children
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public int getItemCount() {
+ if (this.widget == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (this.widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+ return this.children.size();
+ }
+
+ /**
+ * Gets the items.
+ *
+ * @return all children of this item
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public ColumnItem[] getItems() {
+ if (this.widget == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (this.widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+ return this.children.toArray(new ColumnItem[this.children.size()]);
+ }
+
+ /**
+ * Gets the parent.
+ *
+ * @return the widget that holds this item
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public ColumnBrowserWidget getParent() {
+ if (this.widget == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (this.widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+ return this.widget;
+ }
+
+ /**
+ * Gets the parent item.
+ *
+ * @return the parent item, of <code>null</code> if this item is the root
+ * node
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public ColumnItem getParentItem() {
+ if (this.widget == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (this.widget.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+ return this.parent;
+ }
+
+ /**
+ * Return the position of a given item in children's list.
+ *
+ * @param item item to find
+ * @return the position of the children, or -1 if <code>item</code> is a not
+ * a children of this object
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public int indexOf(final ColumnItem item) {
+ return this.children.indexOf(item);
+ }
+
+ /**
+ * Hash code.
+ *
+ * @return the int
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (this.parent == null ? 0 : this.parent.hashCode());
+ result = prime * result + (this.widget == null ? 0 : this.widget.hashCode());
+ return result;
+ }
+
+ /**
+ * Equals.
+ *
+ * @param obj the obj
+ * @return true, if successful
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ColumnItem other = (ColumnItem) obj;
+ if (this.children == null) {
+ if (other.children != null) {
+ return false;
+ }
+ } else if (!this.children.equals(other.children)) {
+ return false;
+ }
+ if (this.parent == null) {
+ if (other.parent != null) {
+ return false;
+ }
+ } else if (!this.parent.equals(other.parent)) {
+ return false;
+ }
+ if (this.widget == null) {
+ if (other.widget != null) {
+ return false;
+ }
+ } else if (!this.widget.equals(other.widget)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicColumnData.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicColumnData.java
new file mode 100644
index 0000000..bad981e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicColumnData.java
@@ -0,0 +1,242 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Luis Carlos Moreira da Costa.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Luis Carlos Moreira da Costa (tcljava at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.dynamictablecolumns;
+
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TreeColumn;
+
+/**
+ *
+ * DynamicColumnData
+ *
+ * <p>Sets the dynamic properties of a column.</p>
+ * <p>The objects of this class must be registered and
+ * handled by an instance of <code>DynamicColumnManager</code></p>
+ * @see org.mihalis.opal.dynamictablecolumns.DynamicTableColumnLayout
+ */
+public class DynamicColumnData {
+
+ /** The preferred length. */
+ private DynamicLength preferredLength = null;
+
+ /** The min length. */
+ private DynamicLength minLength = null;
+
+ /** The visible. */
+ private boolean visible = true;
+
+ /** The table column. */
+ private TableColumn tableColumn = null;
+
+ /** The tree column. */
+ private TreeColumn treeColumn = null;
+
+ /**
+ * <p>Create a dynamic column definition in order to specify
+ * the measures required for a <code>TableColumn</code>.</p>
+ *
+ * <p><b>Definition of length</b>
+ * <br>The lengths are specified using a <code>String</code>, containing
+ * the number, followed by an identifier of measurement.
+ * <br>Ex.: "355px", "100%"</p>
+ *
+ * @param tableColumn TableColumn The column (a table) that should be controlled length.
+ * @param preferredLength String That defines or <i>desired length</i> as column.
+ * @param minLength String That defines or <i>minimum length</i> as column.
+ *
+ * @see org.eclipse.swt.widgets.TableColumn
+ */
+ public DynamicColumnData(final TableColumn tableColumn, final String preferredLength, final String minLength) {
+ this(tableColumn, DynamicLengthFormat.parse(preferredLength), DynamicLengthFormat.parse(minLength));
+ }
+
+ /**
+ * <p>Create a dynamic column definition in order to specify
+ * steps required for a <code>TableColumn</code>.</p>
+ * <p><i>!Builder alternative avoids setting minimum length,
+ * using default 0px !</i></p>
+ *
+ * <p><b>Definition of length</b>
+ * <br>The lengths are specified using a <code>String</code>, containing
+ * quantity, followed by an identifier of measurement.
+ * <br>Ex.: "355px", "100%"</p>
+ *
+ * @param tableColumn TableColumn The column (a table) that should be controlled length.
+ * @param preferredLength String That defines or <i>desired length</i> as column.
+ *
+ * @see org.eclipse.swt.widgets.TableColumn
+ */
+ public DynamicColumnData(final TableColumn tableColumn, final String preferredLength) {
+ this(tableColumn, DynamicLengthFormat.parse(preferredLength), new DynamicLength(0d, DynamicLengthMeasure.PIXEL));
+ }
+
+ /**
+ * <p>Create a dynamic column definition in order to specify
+ * steps required for a <code>TreeColumn</code>.</p>
+ *
+ * <p><b>Definition of length</b>
+ * <br>The lengths are specified using a <code>String</code>, containing
+ * quantity, followed by an identifier of measurement.
+ * <br>Ex.: "355px", "100%"</p>
+ *
+ * @param treeColumn TreeColumn Column (a tree) you want to control the length.
+ * @param preferredLength String That defines or <i>desired length</i> as column.
+ * @param minLength String That defines or <i>minimum length</i> as column.
+ *
+ * @see org.eclipse.swt.widgets.TreeColumn
+ */
+ public DynamicColumnData(final TreeColumn treeColumn, final String preferredLength, final String minLength) {
+ this(treeColumn, DynamicLengthFormat.parse(preferredLength), DynamicLengthFormat.parse(minLength));
+ }
+
+ /**
+ * <p>Create a dynamic column definition in order to specify
+ * steps required for a <code>TreeColumn</code>.</p>
+ * <p><i>!Builder alternative avoids setting minimum length,
+ * using as standard 0px !</i></p>
+ *
+ * <p><b>Definition of length</b>
+ * <br>The lengths are specified using a <code>String</code>, containing
+ * quantity, followed by an identifier of measurement.
+ * <br>Ex.: "355px", "100%"</p>
+ *
+ * @param treeColumn TreeColumn Column (a tree) you want to control the length.
+ * @param preferredLength String That defines or <i>desired length</i> as column.
+ *
+ * @see org.eclipse.swt.widgets.TreeColumn
+ */
+ public DynamicColumnData(final TreeColumn treeColumn, final String preferredLength) {
+ this(treeColumn, DynamicLengthFormat.parse(preferredLength), new DynamicLength(0d, DynamicLengthMeasure.PIXEL));
+ }
+
+ /**
+ * Create a dynamic column definition in order to specify
+ * steps required for a <code>TableColumn</code>.
+ *
+ * @param tableColumn TableColumn The column (a table) that should be controlled length.
+ * @param preferredLength DynamicLength The <i>desired length</i> as column.
+ * @param minLength DynamicLength The <i>minimum length</i> as column.
+ *
+ * @see org.eclipse.swt.widgets.TableColumn
+ */
+ DynamicColumnData(final TableColumn tableColumn, final DynamicLength preferredLength, final DynamicLength minLength) {
+ this.tableColumn = tableColumn;
+ this.preferredLength = preferredLength;
+ this.minLength = minLength;
+ }
+
+ /**
+ * Create a dynamic column definition in order to specify
+ * measures required for a <code>TreeColumn</code>.
+ *
+ * @param treeColumn TreColumn Column (a tree) you want to control the length.
+ * @param preferredLength DynamicLength The <i>desired length</i> as column.
+ * @param minLength DynamicLength The <i>minimum length</i> as column.
+ *
+ * @see org.eclipse.swt.widgets.TreeColumn
+ */
+ DynamicColumnData(final TreeColumn treeColumn, final DynamicLength preferredLength, final DynamicLength minLength) {
+ this.treeColumn = treeColumn;
+ this.preferredLength = preferredLength;
+ this.minLength = minLength;
+ }
+
+ /**
+ * Get preferred length.
+ *
+ * @return the preferred length
+ */
+ public DynamicLength getPreferredLength() {
+ return this.preferredLength;
+ }
+
+ /**
+ * Set preferred length.
+ *
+ * @param preferredLength DynamicLength
+ */
+ public void setPreferredLength(final DynamicLength preferredLength) {
+ this.preferredLength = preferredLength;
+ }
+
+ /**
+ * Get minimal length.
+ *
+ * @return DynamicLength
+ */
+ public DynamicLength getMinLength() {
+ return this.minLength;
+ }
+
+ /**
+ * Set minimal length.
+ *
+ * @param minLength DynamicLength
+ */
+ public void setMinLength(final DynamicLength minLength) {
+ this.minLength = minLength;
+ }
+
+ /**
+ * Get table column.
+ *
+ * @return TableColumn
+ */
+ public TableColumn getTableColumn() {
+ return this.tableColumn;
+ }
+
+ /**
+ * Set table column.
+ *
+ * @param tableColumn TableColumn
+ */
+ public void setTableColumn(final TableColumn tableColumn) {
+ this.tableColumn = tableColumn;
+ }
+
+ /**
+ * Get tree column.
+ *
+ * @return TreeColumn
+ */
+ public TreeColumn getTreeColumn() {
+ return this.treeColumn;
+ }
+
+ /**
+ * Set tree column.
+ *
+ * @param treeColumn TreeColumn
+ */
+ public void setTreeColumn(final TreeColumn treeColumn) {
+ this.treeColumn = treeColumn;
+ }
+
+ /**
+ * Is visible.
+ *
+ * @return boolean
+ */
+ public boolean isVisible() {
+ return this.visible;
+ }
+
+ /**
+ * Set visible.
+ *
+ * @param visible boolean
+ */
+ public void setVisible(final boolean visible) {
+ this.visible = visible;
+ }
+
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLength.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLength.java
new file mode 100644
index 0000000..b2a159f
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLength.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Luis Carlos Moreira da Costa.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Luis Carlos Moreira da Costa (tcljava at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.dynamictablecolumns;
+
+/**
+ * DynamicLength.
+ */
+public class DynamicLength {
+
+ /** The value. */
+ private Double value = 0.0d;
+
+ /** The dynamic length measure. */
+ private DynamicLengthMeasure dynamicLengthMeasure = null;
+
+ /**
+ * Constructor.
+ *
+ * @param value Double
+ * @param dynamicLengthMeasure DynamicLengthMeasure
+ */
+ public DynamicLength(final Double value, final DynamicLengthMeasure dynamicLengthMeasure) {
+ this.value = value;
+ this.dynamicLengthMeasure = dynamicLengthMeasure;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ if ((this.value == null) || (this.dynamicLengthMeasure == null)) {
+ return "";
+ }
+ return (this.value + "" + this.dynamicLengthMeasure.getId());
+ }
+
+ /**
+ * Get value.
+ *
+ * @return Double
+ */
+ public Double getValue() {
+ return this.value;
+ }
+
+ /**
+ * Set value.
+ *
+ * @param value Double
+ */
+ public void setValue(final Double value) {
+ this.value = value;
+ }
+
+ /**
+ * Get measure.
+ *
+ * @return DynamicLengthMeasure
+ */
+ public DynamicLengthMeasure getMeasure() {
+ return this.dynamicLengthMeasure;
+ }
+
+ /**
+ * Set dynamic length measure.
+ *
+ * @param dynamicLengthMeasure DynamicLengthMeasure
+ */
+ public void setMeasure(final DynamicLengthMeasure dynamicLengthMeasure) {
+ this.dynamicLengthMeasure = dynamicLengthMeasure;
+ }
+
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLengthFormat.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLengthFormat.java
new file mode 100644
index 0000000..8bf0f56
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLengthFormat.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Luis Carlos Moreira da Costa.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Luis Carlos Moreira da Costa (tcljava at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.dynamictablecolumns;
+
+/**
+ * DynamicLengthFormat.
+ */
+public class DynamicLengthFormat {
+
+ /**
+ * Parse.
+ *
+ * @param str String
+ * @return DynamicLength
+ */
+ public static DynamicLength parse(final String str) {
+ for (final DynamicLengthMeasure measure : DynamicLengthMeasure.values()) {
+ final int indexOf = str.indexOf(measure.getId());
+
+ if (indexOf >= 0) {
+ final String valuePart = str.substring(0, indexOf).trim();
+ final double value = Double.parseDouble(valuePart);
+ return new DynamicLength(value, measure);
+ }
+ }
+ throw new IllegalArgumentException("Format invalid length");
+ }
+
+ /**
+ * TODO.
+ *
+ * @param dynamicLength DynamicLength
+ * @return String
+ */
+ public static String format(final DynamicLength dynamicLength) {
+ return "";
+ }
+
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLengthMeasure.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLengthMeasure.java
new file mode 100644
index 0000000..df73148
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicLengthMeasure.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Luis Carlos Moreira da Costa.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Luis Carlos Moreira da Costa (tcljava at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.dynamictablecolumns;
+
+/**
+ * DynamicLengthMeasure.
+ */
+public enum DynamicLengthMeasure {
+
+ /** The pixel. */
+ PIXEL("px"), /** The percentage. */
+ PERCENTAGE("%");
+
+ /** The id. */
+ private String id;
+
+ /**
+ * Dynamic Length measure.
+ *
+ * @param id String
+ */
+ private DynamicLengthMeasure(final String id) {
+ this.id = id;
+ }
+
+ /**
+ * Dynamic Length Measure.
+ *
+ * @param id String
+ * @return LengthMeasure
+ */
+ public static DynamicLengthMeasure fromId(final String id) {
+ for (final DynamicLengthMeasure measure : DynamicLengthMeasure.values()) {
+ if (measure.getId().equals(id)) {
+ return measure;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get id.
+ *
+ * @return String
+ */
+ public String getId() {
+ return this.id;
+ }
+
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTable.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTable.java
new file mode 100644
index 0000000..25e656e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTable.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Luis Carlos Moreira da Costa.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Luis Carlos Moreira da Costa (tcljava at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.dynamictablecolumns;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+
+/**
+ * DynamicTable.
+ */
+public class DynamicTable extends Table {
+
+ /** The parent. */
+ private Composite parent = null;
+
+ /** The container. */
+ private Composite container = null;
+
+ /** The header menu. */
+ private Menu headerMenu = null;
+
+ /** The dynamic layout. */
+ private DynamicTableColumnLayout dynamicLayout = null;
+
+ /**
+ * Constructor.
+ *
+ * @param parent Composite
+ * @param style int
+ */
+ public DynamicTable(final Composite parent, final int style) {
+ super(new Composite(parent, SWT.NONE) {
+ @Override
+ public void reskin(final int flags) {
+ super.reskin(flags);
+ }
+ }, style);
+
+ this.parent = parent;
+ this.container = super.getParent();
+
+ this.dynamicLayout = new DynamicTableColumnLayout() {
+ @Override
+ public void setColumnData(final DynamicColumnData column) {
+ super.setColumnData(column);
+ createMenuItem(DynamicTable.this.headerMenu, column);
+ }
+ };
+
+ this.container.setLayout(this.dynamicLayout);
+ this.headerMenu = new Menu(this.container.getShell(), SWT.POP_UP);
+ addListener(SWT.MenuDetect, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ setMenu(((isMouseOverHeader(event.x, event.y)) ? DynamicTable.this.headerMenu : null));
+ }
+ });
+
+ addListener(SWT.Dispose, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ DynamicTable.this.headerMenu.dispose();
+ }
+ });
+ }
+
+ /**
+ * Verify is mouse over header.
+ *
+ * @param x int
+ * @param y int
+ * @return boolean
+ */
+ protected boolean isMouseOverHeader(final int x, final int y) {
+ final Point pt = Display.getDefault().map(null, DynamicTable.this, new Point(x, y));
+ final Rectangle clientArea = getClientArea();
+ return (clientArea.y <= pt.y) && (pt.y < (clientArea.y + getHeaderHeight()));
+ }
+
+ /**
+ * Create menu item.
+ *
+ * @param menu Menu
+ * @param dynamicColumnData DynamicColumnData
+ */
+ private void createMenuItem(final Menu menu, final DynamicColumnData dynamicColumnData) {
+ final TableColumn tableColumn = dynamicColumnData.getTableColumn();
+ final MenuItem itemName = new MenuItem(menu, SWT.CHECK);
+ itemName.setText(tableColumn.getText());
+ itemName.setSelection(tableColumn.getResizable());
+ itemName.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ final boolean checked = itemName.getSelection();
+ dynamicColumnData.setVisible(checked);
+ tableColumn.setResizable(checked);
+ layout();
+ }
+ });
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Composite#getLayout()
+ */
+ @Override
+ public DynamicTableColumnLayout getLayout() {
+ return (DynamicTableColumnLayout) this.container.getLayout();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Composite#setLayout(org.eclipse.swt.widgets.Layout)
+ */
+ @Override
+ public void setLayout(final Layout layout) {
+ throw new IllegalStateException();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Control#setLayoutData(java.lang.Object)
+ */
+ @Override
+ public void setLayoutData(final Object layoutData) {
+ this.container.setLayoutData(layoutData);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Composite#layout()
+ */
+ @Override
+ public void layout() {
+ this.container.layout();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Control#getParent()
+ */
+ @Override
+ public Composite getParent() {
+ return this.parent;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Table#checkSubclass()
+ */
+ @Override
+ protected void checkSubclass() {
+ // Disable the check that prevents subclassing of SWT components.
+ }
+
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumn.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumn.java
new file mode 100644
index 0000000..282f0ac
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumn.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Luis Carlos Moreira da Costa.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Luis Carlos Moreira da Costa (tcljava at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.dynamictablecolumns;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.TableColumn;
+
+/**
+ * DynamicTableColumn.
+ */
+public class DynamicTableColumn extends TableColumn {
+
+ /** The original resizable. */
+ private boolean originalResizable = false;
+
+ /**
+ * Constructor.
+ *
+ * @param parent DynamicTable
+ * @param style int
+ */
+ public DynamicTableColumn(final DynamicTable parent, final int style) {
+ super(parent, style);
+
+ // Config the preferred length of columns.
+ addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ if (getResizable()) {
+ final DynamicTableColumnLayout dynamicLayout = getParent().getLayout();
+ final DynamicColumnData data = dynamicLayout.getColumnData(DynamicTableColumn.this);
+ final DynamicLength preferredfLength = data.getPreferredLength();
+ if (preferredfLength.getMeasure() == DynamicLengthMeasure.PIXEL) {
+ preferredfLength.setValue((double) getWidth());
+ }
+ getParent().layout();
+ }
+ }
+ });
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param parent DynamicTable
+ * @param style int
+ * @param index int
+ */
+ public DynamicTableColumn(final DynamicTable parent, final int style, final int index) {
+ super(parent, style, index);
+ }
+
+ /**
+ * Set width.
+ *
+ * @param preferredLength String
+ */
+ public void setWidth(final String preferredLength) {
+ getParent().getLayout().setColumnData(this, preferredLength);
+ }
+
+ /**
+ * Set width.
+ *
+ * @param preferredLength String
+ * @param minLength String
+ */
+ public void setWidth(final String preferredLength, final String minLength) {
+ final DynamicColumnData columnData = new DynamicColumnData(this, preferredLength, minLength);
+ getParent().getLayout().setColumnData(columnData);
+ setResizable(this.originalResizable);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.TableColumn#setResizable(boolean)
+ */
+ @Override
+ public void setResizable(final boolean resizable) {
+ this.originalResizable = resizable;
+ final DynamicTableColumnLayout dynamicLayout = getParent().getLayout();
+ final DynamicColumnData data = dynamicLayout.getColumnData(DynamicTableColumn.this);
+ super.setResizable(this.originalResizable && data.getPreferredLength().getMeasure() != DynamicLengthMeasure.PERCENTAGE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.TableColumn#getParent()
+ */
+ @Override
+ public DynamicTable getParent() {
+ return (DynamicTable) super.getParent();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.TableColumn#checkSubclass()
+ */
+ @Override
+ protected void checkSubclass() {
+ // Disable the check that prevents subclassing of SWT components.
+ }
+
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumnLayout.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumnLayout.java
new file mode 100644
index 0000000..625b33e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumnLayout.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Luis Carlos Moreira da Costa.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Luis Carlos Moreira da Costa (tcljava at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.dynamictablecolumns;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Scrollable;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TreeColumn;
+
+/**
+ *
+ * DynamicTableColumnLayout
+ *
+ * <p>Manages the length of a set of columns.</p>
+ *
+ */
+public class DynamicTableColumnLayout extends Layout {
+
+ /** The mcolumns. */
+ private final List<DynamicColumnData> mcolumns = new LinkedList<DynamicColumnData>();
+
+ /** The pcolumns. */
+ private final List<DynamicColumnData> pcolumns = new LinkedList<DynamicColumnData>();
+
+ /** The map column data. */
+ private final Map<TableColumn, DynamicColumnData> mapColumnData = new HashMap<TableColumn, DynamicColumnData>();
+
+ /** The installed listeners. */
+ private final Map<Composite, Listener> installedListeners = new HashMap<Composite, Listener>();
+
+ /** The total fixed width. */
+ private int totalFixedWidth = 0;
+
+ /** The total perct width. */
+ private double totalPerctWidth = 0.0d;
+
+ /**
+ * Set dynamic column data.
+ *
+ * @param dynamicColumnData DynamicColumnData
+ */
+ public void setColumnData(final DynamicColumnData dynamicColumnData) {
+ this.mapColumnData.put(dynamicColumnData.getTableColumn(), dynamicColumnData);
+ this.mcolumns.add(dynamicColumnData);
+ if (dynamicColumnData.getPreferredLength().getMeasure() == DynamicLengthMeasure.PERCENTAGE) {
+ this.pcolumns.add(dynamicColumnData);
+ }
+ }
+
+ /**
+ * Set column data.
+ *
+ * @param tableColumn TableColumn
+ * @param preferredLength String
+ * @param minLength String
+ */
+ public void setColumnData(final TableColumn tableColumn, final String preferredLength, final String minLength) {
+ setColumnData(new DynamicColumnData(tableColumn, preferredLength, minLength));
+ }
+
+ /**
+ * Set column data.
+ *
+ * @param tableColumn TableColumn
+ * @param preferredLength String
+ */
+ public void setColumnData(final TableColumn tableColumn, final String preferredLength) {
+ setColumnData(new DynamicColumnData(tableColumn, preferredLength));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Layout#computeSize(org.eclipse.swt.widgets.Composite, int, int, boolean)
+ */
+ @Override
+ protected Point computeSize(final Composite composite, final int wHint, final int hHint, final boolean flushCache) {
+ if (this.installedListeners.get(composite) == null) {
+ final Listener listener = new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ composite.layout();
+ }
+ };
+ composite.addListener(SWT.Resize, listener);
+ this.installedListeners.put(composite, listener);
+ }
+
+ final Control child = composite.getChildren()[0];
+ final Point childSize = child.computeSize(wHint, hHint);
+ int width = Math.max(0, childSize.x);
+ int height = Math.max(0, childSize.y);
+
+ if (wHint != SWT.DEFAULT) {
+ width = wHint;
+ }
+
+ if (hHint != SWT.DEFAULT) {
+ height = hHint;
+ }
+
+ return new Point(width, height);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Layout#layout(org.eclipse.swt.widgets.Composite, boolean)
+ */
+ @Override
+ protected void layout(final Composite composite, final boolean flushCache) {
+ final Rectangle containerArea = composite.getClientArea();
+ final Scrollable table = getControl(composite);
+ table.setBounds(containerArea);
+ final Rectangle tableArea = table.getClientArea();
+ this.totalFixedWidth = 0;
+ this.totalPerctWidth = 0;
+
+ // Calculate totals
+ for (final DynamicColumnData column : this.mcolumns) {
+ if (column.isVisible()) {
+ final DynamicLength prefLength = column.getPreferredLength();
+ final DynamicLength minLength = column.getMinLength();
+
+ if (prefLength.getValue() != 0) {
+ addTotalLength(prefLength);
+ } else {
+ addTotalLength(minLength);
+ }
+ }
+ }
+
+ final Integer precentPixelWidth = (tableArea.width - this.totalFixedWidth);
+
+ // Set widths
+ for (final DynamicColumnData dynamicColumnData : this.mcolumns) {
+ if (dynamicColumnData.isVisible()) {
+ final DynamicLength prefLength = dynamicColumnData.getPreferredLength();
+ final Double prefLengthValue = prefLength.getValue();
+ final DynamicLengthMeasure prefLengthMeasure = prefLength.getMeasure();
+ final DynamicLength minLength = dynamicColumnData.getMinLength();
+ final Double minLengthValue = minLength.getValue();
+ switch (prefLengthMeasure) {
+ case PIXEL:
+ updateColumnWidth(dynamicColumnData, Math.max(prefLengthValue, minLengthValue));
+ break;
+ case PERCENTAGE:
+ final double percentFromTotal = (prefLengthValue / this.totalPerctWidth);
+ final int width = (int) (percentFromTotal * precentPixelWidth);
+ updateColumnWidth(dynamicColumnData, Math.max(width, minLengthValue));
+ }
+ } else {
+ updateColumnWidth(dynamicColumnData, 0d);
+ }
+ }
+ }
+
+ /**
+ * Add total length.
+ *
+ * @param dynamicLength DynamicLength
+ * @return boolean
+ */
+ private boolean addTotalLength(final DynamicLength dynamicLength) {
+ switch (dynamicLength.getMeasure()) {
+ case PIXEL:
+ this.totalFixedWidth += dynamicLength.getValue();
+ break;
+ case PERCENTAGE:
+ this.totalPerctWidth += dynamicLength.getValue();
+ }
+ return (dynamicLength.getValue() != 0);
+ }
+
+ /**
+ * Redistribute percentage.
+ *
+ * @param tableColumn TableColumn
+ * @param value Double
+ */
+ public void redistributePercentage(final TableColumn tableColumn, final Double value) {
+ final int qtdCols = (this.pcolumns.size() - 1);
+ for (final DynamicColumnData data : this.pcolumns) {
+ final DynamicLength preferredLength = data.getPreferredLength();
+ if (tableColumn != data.getTableColumn()) {
+ preferredLength.setValue((preferredLength.getValue() + (value / qtdCols)));
+ }
+ }
+ }
+
+ /**
+ * Update column width.
+ *
+ * @param dynamicColumnData DynamicColumnData
+ * @param width Double
+ */
+ private void updateColumnWidth(final DynamicColumnData dynamicColumnData, final Double width) {
+ final TableColumn tableColumn = dynamicColumnData.getTableColumn();
+ final TreeColumn treeColumn = dynamicColumnData.getTreeColumn();
+
+ if (tableColumn != null) {
+ tableColumn.setWidth(width.intValue());
+ } else if (treeColumn != null) {
+ treeColumn.setWidth(width.intValue());
+ } else {
+ throw new IllegalStateException("No valid to set the column width!");
+ }
+ }
+
+ /**
+ * Get column data.
+ *
+ * @param tableColumn TableColumn
+ * @return DynamicColumnData
+ */
+ public DynamicColumnData getColumnData(final TableColumn tableColumn) {
+ return this.mapColumnData.get(tableColumn);
+ }
+
+ /**
+ * Get control.
+ *
+ * @param composite Composite
+ * @return Scrollable
+ */
+ Scrollable getControl(final Composite composite) {
+ return ((Scrollable) composite.getChildren()[0]);
+ }
+
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTreeColumnLayout.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTreeColumnLayout.java
new file mode 100644
index 0000000..3a5e4c5
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/dynamictablecolumns/DynamicTreeColumnLayout.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Luis Carlos Moreira da Costa.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Luis Carlos Moreira da Costa (tcljava at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.dynamictablecolumns;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Scrollable;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TreeColumn;
+
+/**
+ *
+ * DynamicTreeColumnLayout
+ *
+ * <p>Manages the length of a set of columns.</p>
+ *
+ */
+public class DynamicTreeColumnLayout extends Layout {
+
+ /** The mcolumns. */
+ private final List<DynamicColumnData> mcolumns = new LinkedList<DynamicColumnData>();
+
+ /** The installed listeners. */
+ private final Map<Composite, Listener> installedListeners = new HashMap<Composite, Listener>();
+
+ /** The total fixed width. */
+ private int totalFixedWidth = 0;
+
+ /** The total perct width. */
+ private double totalPerctWidth = 0.0d;
+
+ /** The percentage margin. */
+ private final int percentageMargin = 18;
+
+ /** The relayout. */
+ private boolean relayout = true;
+
+ /**
+ * Set column data.
+ *
+ * @param dynamicColumnData DynamicColumnData
+ */
+ public void setColumnData(final DynamicColumnData dynamicColumnData) {
+ this.mcolumns.add(dynamicColumnData);
+ }
+
+ /**
+ * Set column data.
+ *
+ * @param tableColumn TableColumn
+ * @param preferredLength String
+ * @param minLength String
+ */
+ public void setColumnData(final TableColumn tableColumn, final String preferredLength, final String minLength) {
+ this.mcolumns.add(new DynamicColumnData(tableColumn, preferredLength, minLength));
+ }
+
+ /**
+ * Set column data.
+ *
+ * @param tableColumn TableColumn
+ * @param preferredLength String
+ */
+ public void setColumnData(final TableColumn tableColumn, final String preferredLength) {
+ this.mcolumns.add(new DynamicColumnData(tableColumn, preferredLength));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Layout#computeSize(org.eclipse.swt.widgets.Composite, int, int, boolean)
+ */
+ @Override
+ protected Point computeSize(final Composite composite, final int wHint, final int hHint, final boolean flushCache) {
+ if (this.installedListeners.get(composite) == null) {
+ final Listener listener = new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ event.doit = false;
+ calculate(composite.getBounds().width);
+ }
+ };
+ composite.addListener(SWT.Resize, listener);
+ this.installedListeners.put(composite, listener);
+ }
+ final Point result = ((Scrollable) composite.getChildren()[0]).computeSize(wHint, hHint);
+ calculate(result.x);
+ return result;
+ }
+
+ /**
+ * Calculate.
+ *
+ * @param containerWidth int
+ */
+ public void calculate(final int containerWidth) {
+ this.totalFixedWidth = 0;
+ this.totalPerctWidth = 0;
+
+ // Calculate Totals
+ for (final DynamicColumnData column : this.mcolumns) {
+ final DynamicLength preferredLength = column.getPreferredLength();
+
+ switch (preferredLength.getMeasure()) {
+ case PIXEL:
+ this.totalFixedWidth += preferredLength.getValue();
+ break;
+ case PERCENTAGE:
+ this.totalPerctWidth += preferredLength.getValue();
+ }
+ }
+
+ final Integer precentPixelWidth = (containerWidth - this.totalFixedWidth - this.percentageMargin);
+
+ // Set widths
+ for (final DynamicColumnData mcolumn : this.mcolumns) {
+ final DynamicLength prefLength = mcolumn.getPreferredLength();
+ final Double prefLengthValue = prefLength.getValue();
+ final DynamicLengthMeasure prefLengthMeasure = prefLength.getMeasure();
+ final DynamicLength minLength = mcolumn.getMinLength();
+ final Double minLengthValue = minLength.getValue();
+
+ switch (prefLengthMeasure) {
+ case PIXEL:
+ updateColumnWidth(mcolumn, Math.max(prefLengthValue, minLengthValue));
+ break;
+ case PERCENTAGE:
+ final double percentFromTotal = (prefLengthValue / this.totalPerctWidth);
+ final int width = (int) (percentFromTotal * precentPixelWidth);
+ updateColumnWidth(mcolumn, Math.max(width, minLengthValue));
+ }
+ }
+ }
+
+ /**
+ * Update column width.
+ *
+ * @param dynamicColumnData DynamicColumnData
+ * @param width Double
+ */
+ private void updateColumnWidth(final DynamicColumnData dynamicColumnData, final Double width) {
+ final TableColumn tableColumn = dynamicColumnData.getTableColumn();
+ final TreeColumn treeColumn = dynamicColumnData.getTreeColumn();
+
+ if (tableColumn != null) {
+ tableColumn.setWidth(width.intValue());
+ } else if (treeColumn != null) {
+ treeColumn.setWidth(width.intValue());
+ } else {
+ throw new IllegalStateException("No valid to set the column width!");
+ }
+ }
+
+ /**
+ * Get managed columns.
+ *
+ * @return List<DynamicColumnData>
+ */
+ public List<DynamicColumnData> getManagedColumns() {
+ return this.mcolumns;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Layout#layout(org.eclipse.swt.widgets.Composite, boolean)
+ */
+ @Override
+ protected void layout(final Composite composite, final boolean flushCache) {
+ final Rectangle rect = composite.getClientArea();
+ final Control[] children = composite.getChildren();
+ final int count = children.length;
+
+ if (count == 0) {
+ return;
+ }
+
+ final int width = rect.width;
+ final int height = rect.height;
+ final int x = rect.x;
+ final int extra = (width % count);
+ final int y = rect.y;
+ final int cellWidth = (width / count);
+ final Control child = children[0];
+ int childWidth = cellWidth;
+ childWidth += (extra / 2);
+ child.setBounds(x, y, childWidth, height);
+
+ // For the first time we need to relayout because Scrollbars are not calculate appropriately.
+ if (this.relayout) {
+ this.relayout = false;
+ composite.layout();
+ }
+ }
+
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/flatButton/FlatButton.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/flatButton/FlatButton.java
new file mode 100644
index 0000000..e7158a4
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/flatButton/FlatButton.java
@@ -0,0 +1,664 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.flatButton;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class represent a flat button.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>UP, DOWN, LEFT, RIGHT, CENTER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles LEFT, RIGHT, and CENTER may be specified.
+ * </p>
+ *
+ */
+public class FlatButton extends Canvas {
+
+ /** The Constant DEFAULT_PADDING. */
+ private static final int DEFAULT_PADDING = 5;
+
+ /** The image. */
+ private Image image;
+
+ /** The text. */
+ private String text;
+
+ /** The selection. */
+ private boolean selection;
+
+ /** The alignment. */
+ private int alignment;
+
+ /** The listeners. */
+ private final List<SelectionListener> listeners;
+
+ /** The mouse in. */
+ private boolean mouseIn;
+
+ /** The background color. */
+ private Color backgroundColor;
+
+ /** The selected color. */
+ private Color selectedColor;
+
+ /** The selected text color. */
+ private Color selectedTextColor;
+
+ /** The mouse over color. */
+ private Color mouseOverColor;
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a composite control which will be the parent of the new
+ * instance (cannot be null)
+ * @param style the style of control to construct
+ * @see SWT#DOWN
+ * @see SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#CENTER
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an
+ * allowed subclass</li>
+ * </ul>
+ */
+ public FlatButton(final Composite parent, final int style) {
+ super(parent, style);
+ this.listeners = new ArrayList<SelectionListener>();
+ buildAlignmentFromStyle(style);
+ addListeners();
+ initializeDefaultColors();
+ }
+
+ /**
+ * Builds the alignment from style.
+ *
+ * @param style the style
+ */
+ private void buildAlignmentFromStyle(final int style) {
+ if ((style & SWT.LEFT) == SWT.LEFT) {
+ this.alignment = SWT.LEFT;
+ } else if ((style & SWT.RIGHT) == SWT.RIGHT) {
+ this.alignment = SWT.RIGHT;
+ } else {
+ this.alignment = SWT.CENTER;
+
+ }
+ }
+
+ /**
+ * Adds the listeners.
+ */
+ private void addListeners() {
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(final PaintEvent e) {
+ FlatButton.this.paintControl(e);
+ }
+ });
+
+ addListener(SWT.MouseEnter, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ FlatButton.this.mouseIn = true;
+ redraw();
+ }
+ });
+
+ addListener(SWT.MouseExit, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ FlatButton.this.mouseIn = false;
+ redraw();
+ }
+ });
+
+ addListener(SWT.MouseUp, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ boolean doIt = true;
+ FlatButton.this.selection = !FlatButton.this.selection;
+ for (final SelectionListener listener : FlatButton.this.listeners) {
+ final SelectionEvent sEvent = new SelectionEvent(event);
+ listener.widgetSelected(sEvent);
+ doIt = doIt && sEvent.doit;
+ }
+ if (!doIt) {
+ FlatButton.this.selection = !FlatButton.this.selection;
+ }
+ }
+
+ });
+ }
+
+ /**
+ * Initialize default colors.
+ */
+ private void initializeDefaultColors() {
+ this.backgroundColor = getDisplay().getSystemColor(SWT.COLOR_WHITE);
+ this.selectedColor = new Color(getDisplay(), 0, 112, 192);
+ this.selectedTextColor = getDisplay().getSystemColor(SWT.COLOR_WHITE);
+ this.mouseOverColor = new Color(getDisplay(), 235, 234, 226);
+
+ SWTGraphicUtil.addDisposer(this, this.selectedColor);
+ SWTGraphicUtil.addDisposer(this, this.mouseOverColor);
+ SWTGraphicUtil.addDisposer(this, this.image);
+ }
+
+ /**
+ * Paint control.
+ *
+ * @param e the e
+ */
+ private void paintControl(final PaintEvent e) {
+ final GC gc = e.gc;
+ drawBackground(gc);
+ if (this.image != null) {
+ drawImage(gc);
+ }
+ if (this.text != null) {
+ drawText(gc);
+ }
+ }
+
+ /**
+ * Draw background.
+ *
+ * @param gc the gc
+ */
+ private void drawBackground(final GC gc) {
+ Color color;
+ if (this.selection) {
+ color = this.selectedColor;
+ } else if (this.mouseIn) {
+ color = this.mouseOverColor;
+ } else {
+ color = this.backgroundColor;
+ }
+ gc.setBackground(color);
+ gc.fillRectangle(getClientArea());
+
+ }
+
+ /**
+ * Draw image.
+ *
+ * @param gc the gc
+ */
+ private void drawImage(final GC gc) {
+ final Rectangle rect = getClientArea();
+ final Point imageSize = new Point(this.image.getBounds().width, this.image.getBounds().height);
+
+ int x;
+ if (this.alignment == SWT.LEFT) {
+ x = DEFAULT_PADDING;
+ } else if (this.alignment == SWT.RIGHT) {
+ x = rect.width - imageSize.x - DEFAULT_PADDING;
+ } else {
+ x = (rect.width - imageSize.x) / 2;
+ }
+ gc.drawImage(this.image, x, DEFAULT_PADDING);
+ }
+
+ /**
+ * Draw text.
+ *
+ * @param gc the gc
+ */
+ private void drawText(final GC gc) {
+ final Rectangle rect = getClientArea();
+
+ if (this.selection) {
+ gc.setForeground(this.selectedTextColor);
+ } else {
+ gc.setForeground(getForeground());
+ }
+
+ gc.setFont(getFont());
+ final Point textSize = gc.stringExtent(this.text);
+ int x, y;
+
+ if (this.alignment == SWT.LEFT) {
+ x = DEFAULT_PADDING;
+ } else if (this.alignment == SWT.RIGHT) {
+ x = rect.width - textSize.x - DEFAULT_PADDING;
+ } else {
+ x = (rect.width - textSize.x) / 2;
+ }
+ if (this.image == null) {
+ y = DEFAULT_PADDING;
+ } else {
+ y = 2 * DEFAULT_PADDING + this.image.getBounds().height;
+ }
+ gc.drawString(this.text, x, y, true);
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified
+ * when the control is selected by the user, by sending it one of the
+ * messages defined in the <code>SelectionListener</code> interface.
+ * <p>
+ * <code>widgetSelected</code> is called when the control is selected by the
+ * user. <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void addSelectionListener(final SelectionListener listener) {
+ checkWidget();
+ this.listeners.add(listener);
+ }
+
+ /**
+ * Compute size.
+ *
+ * @param wHint the w hint
+ * @param hHint the h hint
+ * @param changed the changed
+ * @return the point
+ * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)
+ */
+ @Override
+ public Point computeSize(final int wHint, final int hHint, final boolean changed) {
+ int width = 2 * DEFAULT_PADDING, height = 3 * DEFAULT_PADDING;
+ if (this.image != null) {
+ final Rectangle bounds = this.image.getBounds();
+ width += bounds.width;
+ height += bounds.height;
+ }
+
+ if (this.text != null) {
+ final GC gc = new GC(this);
+ final Point extent = gc.stringExtent(this.text);
+ gc.dispose();
+ width = Math.max(width, extent.x + 2 * DEFAULT_PADDING);
+ height = height + extent.y;
+ }
+
+ return new Point(Math.max(width, wHint), Math.max(height, hHint));
+ }
+
+ /**
+ * Returns a value which describes the position of the text in the receiver.
+ * The value will be one of <code>LEFT</code>, <code>RIGHT</code> or
+ * <code>CENTER</code>.
+ *
+ * @return the alignment
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public int getAlignment() {
+ checkWidget();
+ return this.alignment;
+ }
+
+ /**
+ * Returns a value which describes the default background color.
+ *
+ * @return the default background color
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Color getBackgroundColor() {
+ checkWidget();
+ return this.backgroundColor;
+ }
+
+ /**
+ * Returns the receiver's image if it has one, or null if it does not.
+ *
+ * @return the receiver's image
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Image getImage() {
+ checkWidget();
+ return this.image;
+ }
+
+ /**
+ * Returns a value which describes the color when the mouse is over the
+ * button.
+ *
+ * @return the color when the mouse is over the button
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Color getMouseOverColor() {
+ checkWidget();
+ return this.mouseOverColor;
+ }
+
+ /**
+ * Returns a value which describes the color when the button is selected.
+ *
+ * @return the color when the button is selected
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Color getSelectedColor() {
+ checkWidget();
+ return this.selectedColor;
+ }
+
+ /**
+ * Returns a value which describes the color of the text when the button is
+ * selected.
+ *
+ * @return the color of the text when the button is selected
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+
+ public Color getSelectedTextColor() {
+ return this.selectedTextColor;
+ }
+
+ /**
+ * Returns <code>true</code> if the receiver is selected, and false
+ * otherwise.
+ * <p>
+ *
+ * @return the selection state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not
+ * called from the thread that created the receiver</li>
+ * </ul>
+ */
+ public boolean getSelection() {
+ checkWidget();
+ return this.selection;
+ }
+
+ /**
+ * Returns the receiver's text.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public String getText() {
+ checkWidget();
+ return this.text;
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be
+ * notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ * @see SelectionListener
+ * @see #addSelectionListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void removeSelectionListener(final SelectionListener listener) {
+ checkWidget();
+ this.listeners.remove(listener);
+ }
+
+ /**
+ * Controls how text, images and arrows will be displayed in the receiver.
+ * The argument should be one of <code>LEFT</code>, <code>RIGHT</code> or
+ * <code>CENTER</code>.
+ *
+ * @param alignment the new alignment
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setAlignment(final int alignment) {
+ checkWidget();
+ if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) {
+ return;
+ }
+ this.alignment = alignment;
+ redraw();
+ }
+
+ /**
+ * Sets the receiver's background color to the color specified by the
+ * argument.
+ *
+ * @param backgroundColor the new background color
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setBackgroundColor(final Color backgroundColor) {
+ checkWidget();
+ this.backgroundColor = backgroundColor;
+ }
+
+ /**
+ * Sets the receiver's image to the argument, which may be <code>null</code>
+ * indicating that no image should be displayed.
+ * <p>
+ * Note that a Button can display an image and text simultaneously on
+ * Windows (starting with XP), GTK+ and OSX. On other platforms, a Button
+ * that has an image and text set into it will display the image or text
+ * that was set most recently.
+ * </p>
+ *
+ * @param image the image to display on the receiver (may be
+ * <code>null</code>)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setImage(final Image image) {
+ checkWidget();
+ this.image = image;
+ redraw();
+ }
+
+ /**
+ * Sets the receiver's color when the mouse if over the button.
+ *
+ * @param mouseOverColor the new mouse over color
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setMouseOverColor(final Color mouseOverColor) {
+ checkWidget();
+ this.mouseOverColor = mouseOverColor;
+ }
+
+ /**
+ * Sets the receiver's color when the button is selected.
+ *
+ * @param selectedColor the new selected color
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setSelectedColor(final Color selectedColor) {
+ checkWidget();
+ this.selectedColor = selectedColor;
+ }
+
+ /**
+ * Sets the receiver's text color when the button is selected.
+ *
+ * @param selectedTextColor the new selected text color
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setSelectedTextColor(final Color selectedTextColor) {
+ this.selectedTextColor = selectedTextColor;
+ }
+
+ /**
+ * Sets the selection state of the receiver.
+ *
+ * @param selected the new selection state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setSelection(final boolean selected) {
+ checkWidget();
+ this.selection = selected;
+ redraw();
+ }
+
+ /**
+ * Sets the receiver's text.
+ *
+ * @param text the new text
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setText(final String text) {
+ checkWidget();
+ this.text = text;
+ redraw();
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/gradientComposite/GradientComposite.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/gradientComposite/GradientComposite.java
new file mode 100644
index 0000000..744730d
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/gradientComposite/GradientComposite.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial implementation and API
+ *******************************************************************************/
+package org.mihalis.opal.gradientComposite;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Widget;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are controls which background's texture is a gradient
+ * composite.
+ */
+public class GradientComposite extends Composite {
+
+ /** The previous generated image. */
+ private Image previousGeneratedImage;
+
+ /** The gradient end. */
+ private Color gradientEnd;
+
+ /** The gradient start. */
+ private Color gradientStart;
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance
+ * (cannot be null)
+ * @param style the style of widget to construct
+ * @see Composite#Composite(Composite, int)
+ * @see SWT#NO_BACKGROUND
+ * @see SWT#NO_FOCUS
+ * @see SWT#NO_MERGE_PAINTS
+ * @see SWT#NO_REDRAW_RESIZE
+ * @see SWT#NO_RADIO_GROUP
+ * @see SWT#EMBEDDED
+ * @see SWT#DOUBLE_BUFFERED
+ * @see Widget#getStyle
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ public GradientComposite(final Composite parent, final int style) {
+ super(parent, style);
+ this.addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ GradientComposite.this.redrawComposite();
+ }
+ });
+
+ this.gradientStart = getDisplay().getSystemColor(SWT.COLOR_BLACK);
+ this.gradientEnd = SWTGraphicUtil.getDefaultColor(this, 110, 110, 110);
+ }
+
+ /**
+ * Redraws the composite.
+ */
+ private void redrawComposite() {
+ final Display display = this.getDisplay();
+ final Rectangle rect = this.getClientArea();
+ final Image newImage = new Image(display, Math.max(1, rect.width), Math.max(1, rect.height));
+
+ final GC gc = new GC(newImage);
+ gc.setForeground(this.gradientStart);
+ gc.setBackground(this.gradientEnd);
+ gc.fillGradientRectangle(rect.x, rect.y, rect.width, rect.height / 2, true);
+
+ gc.setForeground(this.gradientEnd);
+ gc.setBackground(this.gradientStart);
+ gc.fillGradientRectangle(rect.x, rect.height / 2, rect.width, rect.height / 2, true);
+ gc.dispose();
+
+ this.setBackgroundImage(newImage);
+ if (this.previousGeneratedImage != null) {
+ this.previousGeneratedImage.dispose();
+ }
+ this.previousGeneratedImage = newImage;
+
+ }
+
+ // ------------------------------------ Getters and Setters
+ /**
+ * Gets the gradient end.
+ *
+ * @return the gradientEnd color
+ */
+ public Color getGradientEnd() {
+ return this.gradientEnd;
+ }
+
+ /**
+ * Sets the gradient end.
+ *
+ * @param gradientEnd the gradientEnd color to set
+ */
+ public void setGradientEnd(final Color gradientEnd) {
+ this.gradientEnd = gradientEnd;
+ }
+
+ /**
+ * Gets the gradient start.
+ *
+ * @return the gradientStart color
+ */
+ public Color getGradientStart() {
+ return this.gradientStart;
+ }
+
+ /**
+ * Sets the gradient start.
+ *
+ * @param gradientStart the gradientStart color to set
+ */
+ public void setGradientStart(final Color gradientStart) {
+ this.gradientStart = gradientStart;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/header/Header.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/header/Header.java
new file mode 100644
index 0000000..6a5f406
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/header/Header.java
@@ -0,0 +1,566 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron@gmail.com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.header;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class provide a header, which is composed of a text, a
+ * description and an image.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ */
+public class Header extends Composite {
+
+ /** The image. */
+ private Image image;
+
+ /** The title. */
+ private String title;
+
+ /** The description. */
+ private String description;
+
+ /** The title font. */
+ private Font titleFont;
+
+ /** The title color. */
+ private Color titleColor;
+
+ /** The previous generated image. */
+ private Image previousGeneratedImage;
+
+ /** The gradient end. */
+ private Color gradientEnd;
+
+ /** The gradient start. */
+ private Color gradientStart;
+
+ /** The separator color. */
+ private Color separatorColor;
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a composite control which will be the parent of the new
+ * instance (cannot be null)
+ * @param style the style of control to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ *
+ */
+ public Header(final Composite parent, final int style) {
+ super(parent, style);
+
+ initFontAndColors();
+
+ setBackgroundMode(SWT.INHERIT_FORCE);
+
+ this.addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ redrawComposite();
+ }
+ });
+ }
+
+ /**
+ * Inits the font and colors.
+ */
+ private void initFontAndColors() {
+ final Font defaultFont;
+ final FontData[] fontData = getFont().getFontData();
+ if (fontData != null && fontData.length > 0) {
+ final FontData fd = fontData[0];
+ fd.setStyle(SWT.BOLD);
+ fd.setHeight(fd.getHeight() + 2);
+ defaultFont = new Font(getDisplay(), fd);
+ } else {
+ defaultFont = null;
+ }
+ this.titleFont = defaultFont;
+ SWTGraphicUtil.addDisposer(this, defaultFont);
+
+ final Color defaultTitleColor = new Color(getDisplay(), 0, 88, 150);
+ this.titleColor = defaultTitleColor;
+ SWTGraphicUtil.addDisposer(this, defaultTitleColor);
+
+ final Color defaultGradientEndColor = new Color(this.getDisplay(), 239, 239, 239);
+ this.gradientEnd = defaultGradientEndColor;
+ SWTGraphicUtil.addDisposer(this, defaultGradientEndColor);
+
+ final Color defaultGradientStartColor = new Color(this.getDisplay(), 255, 255, 255);
+ this.gradientStart = defaultGradientStartColor;
+ SWTGraphicUtil.addDisposer(this, defaultGradientStartColor);
+
+ final Color defaultSeparatorColor = new Color(this.getDisplay(), 229, 229, 229);
+ this.separatorColor = defaultSeparatorColor;
+ SWTGraphicUtil.addDisposer(this, defaultSeparatorColor);
+ }
+
+ /**
+ * Redraw the composite.
+ */
+ private void redrawComposite() {
+ // Dispose previous content
+ for (final Control c : this.getChildren()) {
+ c.dispose();
+ }
+
+ int numberOfColumns = 1;
+ if (this.image != null) {
+ numberOfColumns++;
+ }
+
+ super.setLayout(new GridLayout(numberOfColumns, false));
+ createContent();
+ drawBackground();
+ }
+
+ /**
+ * Create the content (title, image, description).
+ */
+ private void createContent() {
+ if (this.title != null) {
+ createTitle();
+ }
+
+ if (this.image != null) {
+ createImage();
+ }
+
+ if (this.description != null) {
+ createDescription();
+ }
+ }
+
+ /**
+ * Create the title.
+ */
+ private void createTitle() {
+ final Label labelTitle = new Label(this, SWT.NONE);
+ labelTitle.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ labelTitle.setFont(this.titleFont);
+ labelTitle.setForeground(this.titleColor);
+ labelTitle.setText(this.title);
+ }
+
+ /**
+ * Create the image.
+ */
+ private void createImage() {
+
+ int numberOfLines = 1;
+ if (this.title != null && this.description != null) {
+ numberOfLines++;
+ }
+ final Label labelImage = new Label(this, SWT.NONE);
+ labelImage.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, true, 1, numberOfLines));
+ labelImage.setImage(this.image);
+ }
+
+ /**
+ * Create the description.
+ */
+ private void createDescription() {
+ final StyledText labelDescription = new StyledText(this, SWT.WRAP | SWT.READ_ONLY);
+ labelDescription.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+ labelDescription.setEnabled(false);
+ labelDescription.setFont(getFont());
+ labelDescription.setForeground(getForeground());
+ labelDescription.setText(this.description);
+ SWTGraphicUtil.applyHTMLFormating(labelDescription);
+ }
+
+ /**
+ * Draw the background (a gradient+a separator).
+ */
+ private void drawBackground() {
+ final Display display = this.getDisplay();
+ final Rectangle rect = this.getClientArea();
+ final Image newImage = new Image(display, Math.max(1, rect.width), Math.max(1, rect.height));
+
+ final GC gc = new GC(newImage);
+ gc.setForeground(this.gradientStart);
+ gc.setBackground(this.gradientEnd);
+
+ gc.fillGradientRectangle(rect.x, rect.y, rect.width, rect.height, false);
+
+ gc.setForeground(this.separatorColor);
+ gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1);
+
+ gc.dispose();
+
+ this.setBackgroundImage(newImage);
+ if (this.previousGeneratedImage != null) {
+ this.previousGeneratedImage.dispose();
+ }
+ this.previousGeneratedImage = newImage;
+ }
+
+ /**
+ * Sets the layout.
+ *
+ * @param layout the new layout
+ * @see org.eclipse.swt.widgets.Composite#setLayout(org.eclipse.swt.widgets.Layout)
+ */
+ @Override
+ public void setLayout(final Layout layout) {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ // ------------------------------------ Getters and Setters
+
+ /**
+ * Returns the receiver's description if it has one, or null if it does not.
+ *
+ * @return the receiver's description if it has one, or null if it does not
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public String getDescription() {
+ checkWidget();
+ return this.description;
+ }
+
+ /**
+ * Returns the receiver's gradient end color.
+ *
+ * @return the receiver's gradient end color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Color getGradientEnd() {
+ checkWidget();
+ return this.gradientEnd;
+ }
+
+ /**
+ * Returns the receiver's gradient start color.
+ *
+ * @return the receiver's gradient start color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Color getGradientStart() {
+ checkWidget();
+ return this.gradientStart;
+ }
+
+ /**
+ * Returns the receiver's image if it has one, or null if it does not.
+ *
+ * @return the receiver's image if it has one, or null if it does not
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Image getImage() {
+ checkWidget();
+ return this.image;
+ }
+
+ /**
+ * Returns the receiver's separator color.
+ *
+ * @return the receiver's separator color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Color getSeparatorColor() {
+ checkWidget();
+ return this.separatorColor;
+ }
+
+ /**
+ * Returns the receiver's title if it has one, or null if it does not.
+ *
+ * @return the receiver's title if it has one, or null if it does not
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public String getTitle() {
+ checkWidget();
+ return this.title;
+ }
+
+ /**
+ * Returns the title's color.
+ *
+ * @return the title's color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Color getTitleColor() {
+ checkWidget();
+ return this.titleColor;
+ }
+
+ /**
+ * Returns the title's font.
+ *
+ * @return the title's font.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public Font getTitleFont() {
+ checkWidget();
+ return this.titleFont;
+ }
+
+ /**
+ * Sets the receiver's description to the argument, which may be null
+ * indicating that no description should be displayed.
+ *
+ * @param description the description of the header (may be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setDescription(final String description) {
+ checkWidget();
+ this.description = description;
+ }
+
+ /**
+ * Sets the receiver's gradient end color.
+ *
+ * @param gradientEnd the receiver's gradient end color
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setGradientEnd(final Color gradientEnd) {
+ checkWidget();
+ this.gradientEnd = gradientEnd;
+ }
+
+ /**
+ * Sets the receiver's gradient start color.
+ *
+ * @param gradientStart the receiver's gradient start color
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setGradientStart(final Color gradientStart) {
+ checkWidget();
+ this.gradientStart = gradientStart;
+ }
+
+ /**
+ * Sets the receiver's image to the argument, which may be null indicating
+ * that no image should be displayed.
+ *
+ * @param image the image to display on the receiver (may be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setImage(final Image image) {
+ checkWidget();
+ this.image = image;
+ }
+
+ /**
+ * Sets the receiver's separator color.
+ *
+ * @param separatorColor the receiver's separator color
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setSeparatorColor(final Color separatorColor) {
+ this.separatorColor = separatorColor;
+ }
+
+ /**
+ * Sets the receiver's title to the argument, which may be null indicating
+ * that no title should be displayed.
+ *
+ * @param title the title
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setTitle(final String title) {
+ checkWidget();
+ this.title = title;
+ }
+
+ /**
+ * Sets the receiver's title color.
+ *
+ * @param headerColor the receiver's title color
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setTitleColor(final Color headerColor) {
+ checkWidget();
+ this.titleColor = headerColor;
+ }
+
+ /**
+ * Sets the receiver's title font.
+ *
+ * @param headerFont the receiver's title font
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setTitleFont(final Font headerFont) {
+ checkWidget();
+ this.titleFont = headerFont;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/heapManager/HeapManager.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/heapManager/HeapManager.java
new file mode 100644
index 0000000..e04b2fa
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/heapManager/HeapManager.java
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Initial implementation and API
+ *******************************************************************************/
+package org.mihalis.opal.heapManager;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Widget;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are controls that display the memory used, the whole
+ * memory, and contains a button to perform a GC.
+ */
+public class HeapManager extends Composite {
+
+ /** The bar. */
+ private Canvas bar;
+
+ /** The button. */
+ private Button button;
+
+ /** The heap max size. */
+ private int heapMaxSize;
+
+ /** The heap size. */
+ private int heapSize;
+
+ /** The bar border color. */
+ private Color barBorderColor;
+
+ /** The bar inner color. */
+ private Color barInnerColor;
+
+ /** The bar text color. */
+ private Color barTextColor;
+
+ /** The bar gradient color top start. */
+ private Color barGradientColorTopStart;
+
+ /** The bar gradient color top end. */
+ private Color barGradientColorTopEnd;
+
+ /** The bar gradient color middle start. */
+ private Color barGradientColorMiddleStart;
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance
+ * (cannot be null)
+ * @param style the style of widget to construct
+ * @see Composite#Composite(Composite, int)
+ * @see Widget#getStyle
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ public HeapManager(final Composite parent, final int style) {
+ super(parent, style);
+ final GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
+ setLayout(gridLayout);
+
+ createBar();
+ createButton();
+ updateContent();
+ createDefaultColors();
+ }
+
+ /**
+ * Creates the bar that displays the memory.
+ */
+ private void createBar() {
+ this.bar = new Canvas(this, SWT.NONE);
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, false);
+ gd.minimumWidth = 100;
+ gd.heightHint = 30;
+ this.bar.setLayoutData(gd);
+ this.heapMaxSize = (int) (Runtime.getRuntime().maxMemory() / (1024 * 1024));
+ this.bar.addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(final PaintEvent e) {
+ drawBar(e);
+ }
+ });
+ }
+
+ /**
+ * Draw the bar.
+ *
+ * @param e {@link PaintEvent}
+ */
+ private void drawBar(final PaintEvent e) {
+ final GC gc = e.gc;
+ final Rectangle clientArea = this.bar.getClientArea();
+
+ gc.setForeground(this.barBorderColor);
+ gc.setBackground(this.barInnerColor);
+ gc.fillRectangle(clientArea);
+ gc.drawRectangle(clientArea.x, clientArea.y, clientArea.width - 1, clientArea.height - 1);
+
+ final float width = (clientArea.width - 2f) * this.heapSize / this.heapMaxSize;
+
+ gc.setForeground(this.barGradientColorTopStart);
+ gc.setBackground(this.barGradientColorTopEnd);
+ gc.fillGradientRectangle(clientArea.x + 1, clientArea.y + 1, (int) width, clientArea.height / 2, true);
+
+ gc.setForeground(this.barGradientColorMiddleStart);
+ gc.setBackground(this.barBorderColor);
+ gc.fillGradientRectangle(clientArea.x + 1, clientArea.height / 2, (int) width, clientArea.height / 2, true);
+
+ final String message = this.heapSize + " " + ResourceManager.getLabel(ResourceManager.MEGABYTES) + "/" + //
+ this.heapMaxSize + " " + ResourceManager.getLabel(ResourceManager.MEGABYTES);
+ final Point size = gc.stringExtent(message);
+
+ gc.setForeground(this.barTextColor);
+ gc.setFont(getFont());
+ gc.drawText(message, (clientArea.width - size.x) / 2, (clientArea.height - size.y) / 2, true);
+
+ gc.dispose();
+
+ }
+
+ /**
+ * Create the button used to perform GC.
+ */
+ private void createButton() {
+ this.button = new Button(this, SWT.PUSH);
+ final Image image = SWTGraphicUtil.createImageFromFile("images/trash.png");
+ this.button.setImage(image);
+ SWTGraphicUtil.addDisposer(this.button, image);
+ this.button.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ this.button.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ // SONAR is not amused about self initiated garbage collector calls!
+// System.gc();
+ }
+ });
+ this.button.setToolTipText(ResourceManager.getLabel(ResourceManager.PERFORM_GC));
+ this.button.pack();
+ }
+
+ /**
+ * Update the content of the bar.
+ */
+ private void updateContent() {
+ getDisplay().timerExec(500, new Runnable() {
+ @Override
+ public void run() {
+ HeapManager.this.heapSize = (int) (Runtime.getRuntime().totalMemory() / (1024 * 1024));
+ if (!isDisposed()) {
+ HeapManager.this.bar.redraw();
+ if (!getDisplay().isDisposed()) {
+ getDisplay().timerExec(500, this);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Creates the default colors.
+ */
+ private void createDefaultColors() {
+ this.barTextColor = SWTGraphicUtil.getDefaultColor(this, 57, 98, 149);
+ this.barInnerColor = SWTGraphicUtil.getDefaultColor(this, 219, 230, 243);
+ this.barBorderColor = SWTGraphicUtil.getDefaultColor(this, 101, 148, 207);
+ this.barGradientColorTopStart = SWTGraphicUtil.getDefaultColor(this, 175, 202, 237);
+ this.barGradientColorTopEnd = SWTGraphicUtil.getDefaultColor(this, 136, 177, 229);
+ this.barGradientColorMiddleStart = SWTGraphicUtil.getDefaultColor(this, 112, 161, 223);
+ }
+
+ /**
+ * Gets the bar border color.
+ *
+ * @return the barBorderColor
+ */
+ public Color getBarBorderColor() {
+ return this.barBorderColor;
+ }
+
+ /**
+ * Sets the bar border color.
+ *
+ * @param barBorderColor the barBorderColor to set
+ */
+ public void setBarBorderColor(final Color barBorderColor) {
+ this.barBorderColor = barBorderColor;
+ }
+
+ /**
+ * Gets the bar inner color.
+ *
+ * @return the barInnerColor
+ */
+ public Color getBarInnerColor() {
+ return this.barInnerColor;
+ }
+
+ /**
+ * Sets the bar inner color.
+ *
+ * @param barInnerColor the barInnerColor to set
+ */
+ public void setBarInnerColor(final Color barInnerColor) {
+ this.barInnerColor = barInnerColor;
+ }
+
+ /**
+ * Gets the bar text color.
+ *
+ * @return the barTextColor
+ */
+ public Color getBarTextColor() {
+ return this.barTextColor;
+ }
+
+ /**
+ * Sets the bar text color.
+ *
+ * @param barTextColor the barTextColor to set
+ */
+ public void setBarTextColor(final Color barTextColor) {
+ this.barTextColor = barTextColor;
+ }
+
+ /**
+ * Gets the bar gradient color top start.
+ *
+ * @return the barGradientColorTopStart
+ */
+ public Color getBarGradientColorTopStart() {
+ return this.barGradientColorTopStart;
+ }
+
+ /**
+ * Sets the bar gradient color top start.
+ *
+ * @param barGradientColorTopStart the barGradientColorTopStart to set
+ */
+ public void setBarGradientColorTopStart(final Color barGradientColorTopStart) {
+ this.barGradientColorTopStart = barGradientColorTopStart;
+ }
+
+ /**
+ * Gets the bar gradient color top end.
+ *
+ * @return the barGradientColorTopEnd
+ */
+ public Color getBarGradientColorTopEnd() {
+ return this.barGradientColorTopEnd;
+ }
+
+ /**
+ * Sets the bar gradient color top end.
+ *
+ * @param barGradientColorTopEnd the barGradientColorTopEnd to set
+ */
+ public void setBarGradientColorTopEnd(final Color barGradientColorTopEnd) {
+ this.barGradientColorTopEnd = barGradientColorTopEnd;
+ }
+
+ /**
+ * Gets the bar gradient color middle start.
+ *
+ * @return the barGradientColorMiddleStart
+ */
+ public Color getBarGradientColorMiddleStart() {
+ return this.barGradientColorMiddleStart;
+ }
+
+ /**
+ * Sets the bar gradient color middle start.
+ *
+ * @param barGradientColorMiddleStart the barGradientColorMiddleStart to set
+ */
+ public void setBarGradientColorMiddleStart(final Color barGradientColorMiddleStart) {
+ this.barGradientColorMiddleStart = barGradientColorMiddleStart;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/horizontalSpinner/HorizontalSpinner.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/horizontalSpinner/HorizontalSpinner.java
new file mode 100644
index 0000000..10dc3e0
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/horizontalSpinner/HorizontalSpinner.java
@@ -0,0 +1,1161 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Laurent CARON
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent CARON (laurent.caron at gmail dot com) - Implementation
+ *******************************************************************************/
+package org.mihalis.opal.horizontalSpinner;
+
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.events.VerifyListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.utils.StringUtil;
+
+/**
+ * Instances of this class are selectable user interface objects that allow the
+ * user to enter and modify numeric values.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>READ_ONLY, FLAP</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection, Modify</dd>
+ * </dl>
+ * </p>
+ */
+public class HorizontalSpinner extends Composite {
+
+ /**
+ * The Enum ALIGNMENT.
+ */
+ private enum ALIGNMENT {
+
+ /** The left. */
+ LEFT,
+ /** The right. */
+ RIGHT,
+ /** The both. */
+ BOTH
+ };
+
+ /** The modify listeners. */
+ private final List<ModifyListener> modifyListeners = new ArrayList<ModifyListener>();
+
+ /** The selection listeners. */
+ private final List<SelectionListener> selectionListeners = new ArrayList<SelectionListener>();
+
+ /** The left button. */
+ private Button leftButton;
+
+ /** The right button. */
+ private Button rightButton;
+
+ /** The text. */
+ private Text text;
+
+ /** The digits. */
+ private int digits = 0;
+
+ /** The increment. */
+ private int increment = 1;
+
+ /** The maximum. */
+ private int maximum = 0;
+
+ /** The minimum. */
+ private int minimum = 255;
+
+ /** The page increment. */
+ private int pageIncrement = 10;
+
+ /** The stored value. */
+ private int storedValue = 0;
+
+ /** The alignment. */
+ private ALIGNMENT alignment = ALIGNMENT.BOTH;
+
+ /** The decimal format separator. */
+ private final char decimalFormatSeparator;
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a composite control which will be the parent of the new
+ * instance (cannot be null)
+ * @param style the style of control to construct
+ * @see SWT#READ_ONLY
+ * @see SWT#FLAT
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an
+ * allowed subclass</li>
+ * </ul>
+ */
+ public HorizontalSpinner(final Composite parent, final int style) {
+ super(parent, style);
+
+ if ((style & SWT.LEFT) == SWT.LEFT) {
+ this.alignment = ALIGNMENT.LEFT;
+ }
+
+ if ((style & SWT.RIGHT) == SWT.RIGHT) {
+ this.alignment = ALIGNMENT.RIGHT;
+ }
+
+ final GridLayout gd = new GridLayout(3, false);
+ gd.horizontalSpacing = gd.verticalSpacing = 0;
+ gd.marginWidth = gd.marginHeight = 0;
+ this.setLayout(gd);
+
+ this.createContent(style);
+ this.addTextListeners();
+ this.addButtonsListener();
+ this.addModifyListeners();
+
+ this.decimalFormatSeparator = new DecimalFormatSymbols().getDecimalSeparator();
+ }
+
+ /**
+ * Create the content of the widget.
+ *
+ * @param style style of the widget
+ */
+ private void createContent(final int style) {
+ final boolean readOnly = (style & SWT.READ_ONLY) == SWT.READ_ONLY;
+ final boolean flat = (style & SWT.FLAT) == SWT.FLAT;
+ final int buttonStyle = SWT.ARROW | (flat ? SWT.FLAT : SWT.NONE);
+
+ if (this.alignment == ALIGNMENT.BOTH) {
+ createMinusButton(buttonStyle);
+ createText(readOnly);
+ createPlusButton(buttonStyle);
+ } else if (this.alignment == ALIGNMENT.LEFT) {
+ createMinusButton(buttonStyle);
+ createPlusButton(buttonStyle);
+ createText(readOnly);
+ } else {
+ createText(readOnly);
+ createMinusButton(buttonStyle);
+ createPlusButton(buttonStyle);
+ }
+ }
+
+ /**
+ * Create minus button.
+ *
+ * @param buttonStyle button style
+ */
+ private void createMinusButton(final int buttonStyle) {
+ this.leftButton = new Button(this, buttonStyle | SWT.LEFT);
+ this.leftButton.setFont(this.getFont());
+ this.leftButton.setBackground(this.getBackground());
+ this.leftButton.setCursor(this.getCursor());
+ this.leftButton.setEnabled(this.getEnabled());
+ this.leftButton.setFont(this.getFont());
+ this.leftButton.setForeground(this.getForeground());
+ this.leftButton.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ }
+
+ /**
+ * Create the text zone.
+ *
+ * @param readOnly if <code>true</code>, the text is read only
+ */
+ private void createText(final boolean readOnly) {
+ this.text = new Text(this, readOnly ? SWT.READ_ONLY : SWT.NONE);
+ final GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false);
+ gd.minimumWidth = 40;
+ this.text.setLayoutData(gd);
+ }
+
+ /**
+ * Create plus button.
+ *
+ * @param buttonStyle button style
+ */
+ private void createPlusButton(final int buttonStyle) {
+ this.rightButton = new Button(this, buttonStyle | SWT.RIGHT);
+ this.rightButton.setFont(this.getFont());
+ this.rightButton.setBackground(this.getBackground());
+ this.rightButton.setCursor(this.getCursor());
+ this.rightButton.setEnabled(this.getEnabled());
+ this.rightButton.setFont(this.getFont());
+ this.rightButton.setForeground(this.getForeground());
+ this.rightButton.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ }
+
+ /**
+ * Add the text listeners.
+ */
+ private void addTextListeners() {
+ this.text.addVerifyListener(new VerifyListener() {
+ @Override
+ public void verifyText(final VerifyEvent e) {
+ if (e.character != 0 && !Character.isDigit(e.character) && e.keyCode != SWT.BS && e.keyCode != SWT.DEL) {
+ e.doit = false;
+ return;
+ }
+ e.doit = HorizontalSpinner.this.verifyEntryAndStoreValue(e.text, e.keyCode);
+ }
+ });
+
+ this.text.addKeyListener(new KeyAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.KeyAdapter#keyReleased(org.eclipse.swt.events.KeyEvent)
+ */
+ @Override
+ public void keyReleased(final KeyEvent e) {
+ if (e.keyCode == SWT.ARROW_UP) {
+ HorizontalSpinner.this.increaseValue(HorizontalSpinner.this.increment);
+ }
+ if (e.keyCode == SWT.ARROW_DOWN) {
+ HorizontalSpinner.this.decreaseValue(HorizontalSpinner.this.increment);
+ }
+ if (e.keyCode == SWT.PAGE_UP) {
+ HorizontalSpinner.this.increaseValue(HorizontalSpinner.this.pageIncrement);
+ }
+ if (e.keyCode == SWT.PAGE_DOWN) {
+ HorizontalSpinner.this.decreaseValue(HorizontalSpinner.this.pageIncrement);
+ }
+ }
+
+ });
+
+ this.text.addFocusListener(new org.eclipse.swt.events.FocusAdapter() {
+ /**
+ * @see org.eclipse.swt.events.FocusAdapter#focusLost(org.eclipse.swt.events.FocusEvent)
+ */
+ @Override
+ public void focusLost(final org.eclipse.swt.events.FocusEvent e) {
+ if (HorizontalSpinner.this.text.getText().trim().equals("")) {
+ HorizontalSpinner.this.setSelection(HorizontalSpinner.this.storedValue);
+ }
+ }
+ });
+ }
+
+ /**
+ * Verify the entry and store the value in the field storedValue.
+ *
+ * @param entry entry to check
+ * @param keyCode code of the typed key
+ * @return <code>true</code> if the entry if correct, <code>false</code>
+ * otherwise
+ */
+ private boolean verifyEntryAndStoreValue(final String entry, final int keyCode) {
+ final String work;
+ if (keyCode == SWT.DEL) {
+ work = StringUtil.removeCharAt(this.text.getText(), this.text.getCaretPosition());
+ } else if (keyCode == SWT.BS && this.text.getCaretPosition() == 0) {
+ work = StringUtil.removeCharAt(this.text.getText(), this.text.getCaretPosition() - 1);
+ } else if (keyCode == 0) {
+ work = entry;
+ } else {
+ work = StringUtil.insertString(this.text.getText(), entry, this.text.getCaretPosition());
+ }
+
+ try {
+ final double d = Double.parseDouble(work.replace(this.decimalFormatSeparator, '.'));
+ this.storedValue = (int) (d * Math.pow(10, this.getDigits()));
+ } catch (final NumberFormatException nfe) {
+ return false;
+ }
+
+ for (final SelectionListener s : HorizontalSpinner.this.selectionListeners) {
+ s.widgetSelected(null);
+ }
+
+ return true;
+ }
+
+ /**
+ * Add the listener to the buttons.
+ */
+ private void addButtonsListener() {
+ this.leftButton.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ HorizontalSpinner.this.decreaseValue(HorizontalSpinner.this.increment);
+ }
+ });
+
+ this.rightButton.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ HorizontalSpinner.this.increaseValue(HorizontalSpinner.this.increment);
+ }
+ });
+
+ }
+
+ /**
+ * Increase the value stored in this snippet.
+ *
+ * @param value value to increase
+ */
+ private void increaseValue(final int value) {
+ this.setSelection(this.getSelection() + value);
+
+ }
+
+ /**
+ * Decrease the value stored in this snippet.
+ *
+ * @param value value to decrease
+ */
+ private void decreaseValue(final int value) {
+ this.setSelection(this.getSelection() - value);
+ }
+
+ /**
+ * Add the modify listeners.
+ */
+ private void addModifyListeners() {
+ this.text.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(final ModifyEvent e) {
+ for (final ModifyListener m : HorizontalSpinner.this.modifyListeners) {
+ m.modifyText(e);
+ }
+ }
+ });
+
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified
+ * when the receiver's text is modified, by sending it one of the messages
+ * defined in the <code>ModifyListener</code> interface.
+ *
+ * @param listener the listener which should be notified
+ * @see ModifyListener
+ * @see #removeModifyListener
+ * @see org.eclipse.swt.widgets.Spinner#addModifyListener(org.eclipse.swt.events.ModifyListener)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+
+ public void addModifyListener(final ModifyListener listener) {
+ this.checkWidget();
+ this.modifyListeners.add(listener);
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified
+ * when the control is selected by the user, by sending it one of the
+ * messages defined in the <code>SelectionListener</code> interface.
+ * <p>
+ * <code>widgetSelected</code> is not called for texts.
+ * <code>widgetDefaultSelected</code> is typically called when ENTER is
+ * pressed in a single-line text.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the control is
+ * selected by the user
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void addSelectionListener(final SelectionListener listener) {
+ this.checkWidget();
+ this.selectionListeners.add(listener);
+ }
+
+ /**
+ * Copies the selected text.
+ * <p>
+ * The current selection is copied to the clipboard.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void copy() {
+ this.checkWidget();
+ this.text.copy();
+ }
+
+ /**
+ * Cuts the selected text.
+ * <p>
+ * The current selection is first copied to the clipboard and then deleted
+ * from the widget.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void cut() {
+ this.checkWidget();
+ this.text.cut();
+ }
+
+ /**
+ * Returns the number of decimal places used by the receiver.
+ *
+ * @return the digits
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public int getDigits() {
+ this.checkWidget();
+ return this.digits;
+ }
+
+ /**
+ * Returns the amount that the receiver's value will be modified by when the
+ * up/down arrows are pressed.
+ *
+ * @return the increment
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public int getIncrement() {
+ this.checkWidget();
+ return this.increment;
+ }
+
+ /**
+ * Returns the maximum value which the receiver will allow.
+ *
+ * @return the maximum
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public int getMaximum() {
+ this.checkWidget();
+ return this.maximum;
+ }
+
+ /**
+ * Returns the minimum value which the receiver will allow.
+ *
+ * @return the minimum
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public int getMinimum() {
+ this.checkWidget();
+ return this.minimum;
+ }
+
+ /**
+ * Returns the amount that the receiver's position will be modified by when
+ * the page up/down keys are pressed.
+ *
+ * @return the page increment
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public int getPageIncrement() {
+ this.checkWidget();
+ return this.pageIncrement;
+ }
+
+ /**
+ * Returns the <em>selection</em>, which is the receiver's position.
+ *
+ * @return the selection
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public int getSelection() {
+ this.checkWidget();
+ return this.storedValue;
+ }
+
+ /**
+ * Returns a string containing a copy of the contents of the receiver's text
+ * field, or an empty string if there are no contents.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ *
+ */
+ public String getText() {
+ this.checkWidget();
+ return this.text.getText();
+ }
+
+ /**
+ * Returns the maximum number of characters that the receiver's text field
+ * is capable of holding. If this has not been changed by
+ * <code>setTextLimit()</code>, it will be the constant
+ * <code>Spinner.LIMIT</code>.
+ *
+ * @return the text limit
+ * @see #LIMIT
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public int getTextLimit() {
+ this.checkWidget();
+ return this.text.getTextLimit();
+ }
+
+ /**
+ * Pastes text from clipboard.
+ * <p>
+ * The selected text is deleted from the widget and new text inserted from
+ * the clipboard.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void paste() {
+ this.checkWidget();
+ this.text.paste();
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be
+ * notified when the receiver's text is modified.
+ *
+ * @param listener the listener which should no longer be notified
+ * @see ModifyListener
+ * @see #addModifyListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void removeModifyListener(final ModifyListener listener) {
+ this.checkWidget();
+ this.modifyListeners.remove(listener);
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be
+ * notified when the control is selected by the user.
+ *
+ * @param listener the listener which should no longer be notified
+ * @see SelectionListener
+ * @see #addSelectionListener
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void removeSelectionListener(final SelectionListener listener) {
+ this.checkWidget();
+ this.selectionListeners.remove(listener);
+ }
+
+ /**
+ * Sets the number of decimal places used by the receiver.
+ * <p>
+ * The digit setting is used to allow for floating point values in the
+ * receiver. For example, to set the selection to a floating point value of
+ * 1.37 call setDigits() with a value of 2 and setSelection() with a value
+ * of 137. Similarly, if getDigits() has a value of 2 and getSelection()
+ * returns 137 this should be interpreted as 1.37. This applies to all
+ * numeric APIs.
+ * </p>
+ *
+ * @param value the new digits (must be greater than or equal to zero)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the value is less than
+ * zero</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setDigits(final int value) {
+ this.checkWidget();
+ this.digits = value;
+ this.convertSelectionToStringValue();
+ }
+
+ /**
+ * Sets the amount that the receiver's value will be modified by when the
+ * up/down arrows are pressed to the argument, which must be at least one.
+ *
+ * @param value the new increment (must be greater than zero)
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setIncrement(final int value) {
+ this.checkWidget();
+ this.increment = value;
+ }
+
+ /**
+ * Sets the maximum value that the receiver will allow. This new value will
+ * be ignored if it is less than the receiver's current minimum value. If
+ * the new maximum is applied then the receiver's selection value will be
+ * adjusted if necessary to fall within its new range.
+ *
+ * @param value the new maximum, which must be greater than or equal to the
+ * current minimum
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setMaximum(final int value) {
+ this.checkWidget();
+ this.maximum = value;
+ }
+
+ /**
+ * Sets the minimum value that the receiver will allow. This new value will
+ * be ignored if it is greater than the receiver's current maximum value. If
+ * the new minimum is applied then the receiver's selection value will be
+ * adjusted if necessary to fall within its new range.
+ *
+ * @param value the new minimum, which must be less than or equal to the
+ * current maximum
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setMinimum(final int value) {
+ this.checkWidget();
+ this.minimum = value;
+ }
+
+ /**
+ * Sets the amount that the receiver's position will be modified by when the
+ * page up/down keys are pressed to the argument, which must be at least
+ * one.
+ *
+ * @param value the page increment (must be greater than zero)
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setPageIncrement(final int value) {
+ this.checkWidget();
+ this.pageIncrement = value;
+ }
+
+ /**
+ * Sets the <em>selection</em>, which is the receiver's position, to the
+ * argument. If the argument is not within the range specified by minimum
+ * and maximum, it will be adjusted to fall within this range.
+ *
+ * @param selection the new selection
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setSelection(int selection) {
+ this.checkWidget();
+ if (selection < this.minimum) {
+ selection = this.minimum;
+ } else if (selection > this.maximum) {
+ selection = this.maximum;
+ }
+
+ this.storedValue = selection;
+ this.text.setText(this.convertSelectionToStringValue());
+ this.text.selectAll();
+ this.text.setFocus();
+
+ for (final SelectionListener s : HorizontalSpinner.this.selectionListeners) {
+ s.widgetSelected(null);
+ }
+
+ }
+
+ /**
+ * Convert the selection into a string.
+ *
+ * @return the string representation of the selection
+ */
+ private String convertSelectionToStringValue() {
+ if (this.getDigits() == 0) {
+ return String.valueOf(this.storedValue);
+ }
+ final StringBuilder unformatted = new StringBuilder(String.valueOf(this.storedValue * Math.pow(10, -1 * this.getDigits())));
+ for (int i = 0; i < this.digits; i++) {
+ unformatted.append("0");
+ }
+ final int position = unformatted.indexOf(".");
+ final String temp = unformatted.substring(0, position + 1 + this.digits);
+ return temp.replace('.', this.decimalFormatSeparator);
+
+ }
+
+ /**
+ * Sets the maximum number of characters that the receiver's text field is
+ * capable of holding to be the argument.
+ * <p>
+ * To reset this value to the default, use
+ * <code>setTextLimit(Spinner.LIMIT)</code>. Specifying a limit value larger
+ * than <code>Spinner.LIMIT</code> sets the receiver's limit to
+ * <code>Spinner.LIMIT</code>.
+ * </p>
+ *
+ * @param limit new text limit
+ * @see #LIMIT
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setTextLimit(final int limit) {
+ this.checkWidget();
+ this.text.setTextLimit(limit);
+ }
+
+ /**
+ * Sets the receiver's selection, minimum value, maximum value, digits,
+ * increment and page increment all at once.
+ * <p>
+ * Note: This is similar to setting the values individually using the
+ * appropriate methods, but may be implemented in a more efficient fashion
+ * on some platforms.
+ * </p>
+ *
+ * @param selection the new selection value
+ * @param minimum the new minimum value
+ * @param maximum the new maximum value
+ * @param digits the new digits value
+ * @param increment the new increment value
+ * @param pageIncrement the new pageIncrement value
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setValues(final int selection, final int minimum, final int maximum, final int digits, final int increment, final int pageIncrement) {
+ this.setMinimum(minimum);
+ this.setMaximum(maximum);
+ this.setDigits(digits);
+ this.setIncrement(increment);
+ this.setPageIncrement(pageIncrement);
+ this.setSelection(selection);
+ }
+
+ /**
+ * Sets the receiver's drag detect state. If the argument is
+ * <code>true</code>, the receiver will detect drag gestures, otherwise
+ * these gestures will be ignored.
+ *
+ * @return true, if successful
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public boolean setFocus() {
+ this.checkWidget();
+ return this.text.setFocus();
+ }
+
+ /**
+ * Forces the receiver to have the <em>keyboard focus</em>, causing all
+ * keyboard events to be delivered to it.
+ *
+ * @return <code>true</code> if the control got focus, and
+ * <code>false</code> if it was unable to.
+ * @see #setFocus
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public boolean forceFocus() {
+ this.checkWidget();
+ return this.text.forceFocus();
+ }
+
+ /**
+ * Sets the receiver's background color to the color specified by the
+ * argument, or to the default system color for the control if the argument
+ * is null.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform. For
+ * example, on Windows the background of a Button cannot be changed.
+ * </p>
+ *
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setBackground(final Color color) {
+ super.setBackground(color);
+ this.leftButton.setBackground(color);
+ this.rightButton.setBackground(color);
+ this.text.setBackground(color);
+ }
+
+ /**
+ * Sets the receiver's background image to the image specified by the
+ * argument, or to the default system color for the control if the argument
+ * is null. The background image is tiled to fill the available space.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform. For
+ * example, on Windows the background of a Button cannot be changed.
+ * </p>
+ *
+ * @param image the new image (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument is not a
+ * bitmap</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setBackgroundImage(final Image image) {
+ super.setBackgroundImage(image);
+ this.leftButton.setBackgroundImage(image);
+ this.rightButton.setBackgroundImage(image);
+ this.text.setBackgroundImage(image);
+
+ }
+
+ /**
+ * Sets the receiver's cursor to the cursor specified by the argument, or to
+ * the default cursor for that kind of control if the argument is null.
+ * <p>
+ * When the mouse pointer passes over a control its appearance is changed to
+ * match the control's cursor.
+ * </p>
+ *
+ * @param cursor the new cursor (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been
+ * disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setCursor(final Cursor cursor) {
+ super.setCursor(cursor);
+ this.leftButton.setCursor(cursor);
+ this.rightButton.setCursor(cursor);
+ this.text.setCursor(cursor);
+ }
+
+ /**
+ * Enables the receiver if the argument is <code>true</code>, and disables
+ * it otherwise. A disabled control is typically not selectable from the
+ * user interface and draws with an inactive or "grayed" look.
+ *
+ * @param enabled the new enabled state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ @Override
+ public void setEnabled(final boolean enabled) {
+ super.setEnabled(enabled);
+ this.leftButton.setEnabled(enabled);
+ this.rightButton.setEnabled(enabled);
+ this.text.setEnabled(enabled);
+ }
+
+ /**
+ * Sets the font that the receiver will use to paint textual information to
+ * the font speci