Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Mollik2018-02-23 13:38:41 +0000
committerRalf Mollik2018-02-23 13:38:41 +0000
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 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)
+ *
+ * @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);
+ this.text.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)
+ *
+ * @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);
+ this.leftButton.setForeground(color);
+ this.rightButton.setForeground(color);
+ this.text.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
+ *
+ * @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);
+ this.leftButton.setMenu(menu);
+ this.rightButton.setMenu(menu);
+ this.text.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
+ * @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);
+ this.leftButton.setToolTipText(tooltipText);
+ this.rightButton.setToolTipText(tooltipText);
+ this.text.setToolTipText(tooltipText);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ISItem.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ISItem.java
new file mode 100644
index 0000000..de0a946
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ISItem.java
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * 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.imageSelector;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.mihalis.opal.OpalItem;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * 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;
+
+ /**
+ * Constructor.
+ *
+ * @param fileName file name of the image that will be displayed
+ */
+ public ISItem(final String fileName) {
+ setImage(SWTGraphicUtil.createImageFromFile(fileName));
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param title the title of the image
+ * @param fileName file name of the image that will be displayed
+ */
+ public ISItem(final String title, final String fileName) {
+ setImage(SWTGraphicUtil.createImageFromFile(fileName));
+ setText(title);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param title the title of the image
+ * @param img image that will be displayed
+ */
+ public ISItem(final String title, final Image img) {
+ setImage(img);
+ setText(title);
+ }
+
+ /**
+ * Gets the z position.
+ *
+ * @return the zPosition
+ */
+ double getzPosition() {
+ return 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 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) {
+ upperLeftCorner = new Point(x, y);
+ }
+
+ /**
+ * Gets the lower right corner.
+ *
+ * @return the lowerRightCorner
+ */
+ Point getLowerRightCorner() {
+ return 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) {
+ lowerRightCorner = new Point(x, y);
+ }
+
+ /**
+ * Reset corner to null.
+ */
+ void resetCornerToNull() {
+ upperLeftCorner = null;
+ lowerRightCorner = null;
+
+ }
+
+ /**
+ * To string.
+ *
+ * @return the string
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "ISItem [getText()=" + 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(zPosition)).compareTo(Math.abs(o.getzPosition())) * -1;
+ }
+
+ /**
+ * Indicates whether some other {@code ISItem} is "equal" to this one. Two
+ * objects of type {@code ISItem} are considered "equal" if their attributes
+ * {@literal zPosition} are equal.
+ *
+ * If the passed object is null or <b>not</b> of type {@code ISItem} 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
+ * ISItem).
+ * @return {@code true} if this {@code ISItem} is the same as the passed
+ * object of type {@code ISItem}; {@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.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelector.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelector.java
new file mode 100644
index 0000000..8cf7d58
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelector.java
@@ -0,0 +1,679 @@
+/*******************************************************************************
+ * 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.imageSelector;
+
+import java.util.ArrayList;
+import java.util.Collections;
+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.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.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * 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>
+ * Work inspired by Romain Guy's work
+ * (http://www.curious-creature.org/2005/07/09/a-music-shelf-in-java2d/)
+ */
+public class ImageSelector extends Canvas {
+
+ /** The items. */
+ private List<ISItem> items;
+
+ /** The original items. */
+ private List<ISItem> originalItems;
+
+ /** The font. */
+ private Font font;
+
+ /** The Constant DEFAULT_WIDTH. */
+ private static final int DEFAULT_WIDTH = 148;
+
+ /** The max item width. */
+ private int maxItemWidth = DEFAULT_WIDTH;
+
+ /** 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 cached image. */
+ private Image cachedImage;
+
+ /** The cached gc. */
+ private GC cachedGC;
+
+ /**
+ * 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 ImageSelector(final Composite parent, final int style) {
+ super(parent, style | SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
+ final Font defaultFont = new Font(getDisplay(), "Lucida Sans", 24, SWT.NONE);
+ font = defaultFont;
+ SWTGraphicUtil.addDisposer(this, defaultFont);
+
+ setSigma(0.5);
+ gradientStart = getDisplay().getSystemColor(SWT.COLOR_BLACK);
+ gradientEnd = SWTGraphicUtil.getDefaultColor(this, 110, 110, 110);
+
+ addListeners();
+ SWTGraphicUtil.addDisposer(this, cachedGC);
+ SWTGraphicUtil.addDisposer(this, cachedImage);
+ }
+
+ /**
+ * Adds the listeners.
+ */
+ private void addListeners() {
+ addKeyListener();
+ addMouseListeners();
+
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(final PaintEvent e) {
+ ImageSelector.this.paintControl(e);
+ }
+ });
+
+ addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ if (cachedGC == null) {
+ return;
+ }
+ cachedGC.dispose();
+ cachedImage.dispose();
+ cachedImage = new Image(getDisplay(), getClientArea());
+ cachedGC = new GC(cachedImage);
+ cachedGC.setAntialias(SWT.ON);
+ }
+ });
+ }
+
+ /**
+ * 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 * index);
+ break;
+ case SWT.END:
+ scrollBy(index);
+ break;
+ case SWT.PAGE_UP:
+ scrollBy(-1 * pageIncrement);
+ break;
+ case SWT.PAGE_DOWN:
+ scrollBy(pageIncrement);
+ break;
+ }
+ }
+ });
+ }
+
+ /**
+ * Add mouse listeners.
+ */
+ private void addMouseListeners() {
+ addMouseMoveListener(new MouseMoveListener() {
+ @Override
+ public void mouseMove(final MouseEvent e) {
+ for (final ISItem item : 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() {
+ /**
+ * @see org.eclipse.swt.events.MouseAdapter#mouseUp(org.eclipse.swt.events.MouseEvent)
+ */
+ @Override
+ public void mouseUp(final MouseEvent e) {
+ for (final ISItem item : 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(originalItems.indexOf(item) - index);
+ return;
+ }
+ }
+ }
+ });
+
+ addListener(SWT.MouseWheel, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ scrollBy(-1 * event.count);
+ }
+ });
+ }
+
+ /**
+ * Set the sigma value for the gaussian curve.
+ *
+ * @param sigma new sigma parameter
+ */
+ public void setSigma(final double sigma) {
+ this.sigma = sigma;
+ rho = 1.0;
+ computeEquationParts();
+ rho = computeModifierUnbounded(0.0);
+ computeEquationParts();
+ redraw();
+ }
+
+ /**
+ * 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 expMultiplier * Math.exp(-x * x / expMember);
+ }
+
+ /**
+ * Computer both members of the equation.
+ */
+ private void computeEquationParts() {
+ expMultiplier = Math.sqrt(2.0 * Math.PI) / sigma / rho;
+ expMember = 4.0 * sigma * sigma;
+ }
+
+ /**
+ * Draw the widget.
+ *
+ * @param e the paintEvent
+ */
+ private void paintControl(final PaintEvent e) {
+
+ if (cachedImage == null) {
+ cachedImage = new Image(getDisplay(), getClientArea());
+ cachedGC = new GC(cachedImage);
+ cachedGC.setAntialias(SWT.ON);
+ }
+
+ // Draw gradient
+ drawBackground();
+
+ // Draw the items
+ drawItems();
+
+ // Draw the title
+ if (animationStep < 0d) {
+ drawTitle();
+ }
+
+ // Draw the offscreen buffer to the screen
+ e.gc.drawImage(cachedImage, 0, 0);
+ }
+
+ /**
+ * Draw the background.
+ */
+ private void drawBackground() {
+ final Rectangle rect = getClientArea();
+
+ cachedGC.setForeground(gradientStart);
+ cachedGC.setBackground(gradientEnd);
+ cachedGC.fillGradientRectangle(rect.x, rect.y, rect.width, rect.height / 2, true);
+
+ cachedGC.setForeground(gradientEnd);
+ cachedGC.setBackground(gradientStart);
+ cachedGC.fillGradientRectangle(rect.x, rect.height / 2, rect.width, rect.height / 2, true);
+ }
+
+ /**
+ * Draw the items.
+ */
+ private void drawItems() {
+ if (animationStep < 0d) {
+ items.clear();
+ items.addAll(originalItems);
+ for (int i = 0; i < items.size(); i++) {
+ final ISItem item = items.get(i);
+ item.setzPosition((i - index) * spacing);
+ }
+ Collections.sort(items);
+ }
+
+ for (final ISItem item : items) {
+ drawItem(item);
+ }
+ }
+
+ /**
+ * Draw a given item.
+ *
+ * @param item item to draw
+ */
+ private void drawItem(final ISItem item) {
+
+ final int size = computeSize(item);
+ final int centerX = computeZPosition(item);
+ final int centerY = getClientArea().height / 2;
+
+ if (size <= 0 || centerX < 0 || centerX > getBounds().width) {
+ item.resetCornerToNull();
+ return;
+ }
+
+ final int alpha = computeAlpha(item);
+
+ final Image newImage = SWTGraphicUtil.createReflectedResizedImage(item.getImage(), size, size);
+ cachedGC.setAlpha(alpha);
+
+ final int x = centerX - newImage.getBounds().width / 2;
+ final int y = centerY - newImage.getBounds().height / 2;
+
+ cachedGC.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 = getClientArea().width / 2;
+ final int centerX = 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()) * 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.
+ */
+ private void drawTitle() {
+ final String title = originalItems.get(index).getText();
+ if (title == null || title.trim().equals("")) {
+ return;
+ }
+ cachedGC.setFont(getFont());
+ final Point textSize = cachedGC.stringExtent(title);
+
+ cachedGC.setFont(getFont());
+ cachedGC.setForeground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ cachedGC.setAlpha(255);
+
+ final int centerX = getClientArea().width / 2;
+ final int centerY = (getClientArea().height + maxItemWidth) / 2;
+
+ cachedGC.drawString(title, centerX - textSize.x / 2, centerY - textSize.y / 2, true);
+
+ }
+
+ /**
+ * Scroll the selected item.
+ *
+ * @param increment increment value
+ */
+ private void scrollBy(final int increment) {
+ index += increment;
+ if (index < 0) {
+ index = 0;
+ }
+
+ if (index >= items.size()) {
+ index = items.size() - 1;
+ }
+ redraw();
+ }
+
+ /**
+ * Scroll the selected item with an animation.
+ *
+ * @param increment increment value
+ */
+ private void scrollAndAnimateBy(final int increment) {
+ if (increment == 0 || index == 0 && increment < 0 || index == 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() {
+ startAnimation(increment, step);
+ }
+
+ private void startAnimation(final int increment, final double step) {
+ items.clear();
+ items.addAll(originalItems);
+ for (int i = 0; i < items.size(); i++) {
+ final ISItem item = items.get(i);
+ item.setzPosition((i - index + animationStep * (increment > 0 ? -1d : 1d)) * spacing);
+ }
+ Collections.sort(items);
+ if (!isDisposed()) {
+ redraw();
+ }
+
+ animationStep += step;
+ if (animationStep >= 1d) {
+ animationStep = -1d;
+ index += increment;
+ setCursor(getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
+ } else {
+ if (!isDisposed()) {
+ getDisplay().timerExec(TIMER_INTERVAL, this);
+ }
+ }
+ }
+ });
+
+ }
+
+ /**
+ * Gets the items.
+ *
+ * @return the items displayed by this widget
+ */
+ public List<ISItem> getItems() {
+ return 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);
+ originalItems = items;
+ index = this.items.size() / 2;
+ redraw();
+ }
+
+ /**
+ * Gets the font.
+ *
+ * @return the font used for the title
+ */
+ @Override
+ public Font getFont() {
+ return font;
+ }
+
+ /**
+ * Sets the font.
+ *
+ * @param font the font used for the title to set
+ */
+ @Override
+ public void setFont(final Font font) {
+ this.font = font;
+ redraw();
+ }
+
+ /**
+ * Gets the index.
+ *
+ * @return the index of the selected image
+ */
+ public int getIndex() {
+ return 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 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 sigma;
+ }
+
+ /**
+ * Gets the spacing.
+ *
+ * @return the spacing between 2 items
+ */
+ public float getSpacing() {
+ return 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 gradientStart;
+ }
+
+ /**
+ * Sets the gradient start.
+ *
+ * @param gradientStart the the gradient start color to set
+ */
+ public void setGradientStart(final Color gradientStart) {
+ this.gradientStart = gradientStart;
+ redraw();
+ }
+
+ /**
+ * Gets the gradient end.
+ *
+ * @return the the gradient end color
+ */
+ public Color getGradientEnd() {
+ return gradientEnd;
+ }
+
+ /**
+ * Sets the gradient end.
+ *
+ * @param gradientEnd the the gradient end color to set
+ */
+ public void setGradientEnd(final Color gradientEnd) {
+ this.gradientEnd = gradientEnd;
+ redraw();
+ }
+
+ /**
+ * Gets the page increment.
+ *
+ * @return the page increment when the user uses PgUp and PgDown
+ */
+ public int getPageIncrement() {
+ return pageIncrement;
+ }
+
+ /**
+ * Sets the page increment.
+ *
+ * @param pageIncrement the page increment to set
+ */
+ public void setPageIncrement(final int pageIncrement) {
+ this.pageIncrement = pageIncrement;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/infinitePanel/InfiniteProgressPanel.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/infinitePanel/InfiniteProgressPanel.java
new file mode 100644
index 0000000..434f3f8
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/infinitePanel/InfiniteProgressPanel.java
@@ -0,0 +1,665 @@
+/*******************************************************************************
+ * 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.infinitePanel;
+
+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.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are controls located on the top of a shell. They
+ * display a ticker that indicates to the user that a long task operation is
+ * running. The design is inspired by Romain Guy's work
+ * (http://www.curious-creature.org)
+ */
+public class InfiniteProgressPanel {
+
+ /** The Constant INFINITE_PANEL_KEY. */
+ private static final String INFINITE_PANEL_KEY = "org.mihalis.opal.InfinitePanel.InfiniteProgressPanel";
+
+ /** The Constant NUMBER_OF_STEPS. */
+ private static final int NUMBER_OF_STEPS = 10;
+
+ /** The parent. */
+ private final Shell parent;
+
+ /** The shell hover. */
+ private Shell shellHover;
+
+ /** The text. */
+ private String text;
+
+ /** The text font. */
+ private Font textFont;
+
+ /** The text color. */
+ private Color textColor;
+
+ /** The fps. */
+ private float fps;
+
+ /** The bars count. */
+ private int barsCount;
+
+ /** The line width. */
+ private int lineWidth;
+
+ /** The alpha. */
+ private int alpha;
+
+ /** The default color. */
+ private Color defaultColor;
+
+ /** The selection color. */
+ private Color selectionColor;
+
+ /** The current position. */
+ private int currentPosition;
+
+ /** The animator thread. */
+ private Thread animatorThread;
+
+ /** The canvas. */
+ private Canvas canvas;
+
+ /** The fade in. */
+ private boolean fadeIn;
+
+ /** The fade out. */
+ private boolean fadeOut;
+
+ /** The fade out counter. */
+ private int fadeOutCounter;
+
+ /**
+ * Constructs a new instance of this class given its parent.
+ *
+ * @param shell a shell that will be the parent of the new instance (cannot
+ * 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 parent has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ private InfiniteProgressPanel(final Shell shell) {
+ if (shell == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (shell.isDisposed()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ parent = shell;
+ if (shell.getData(INFINITE_PANEL_KEY) != null) {
+ throw new IllegalArgumentException("This shell has already an infinite panel attached on it !");
+ }
+
+ text = null;
+ textFont = null;
+ barsCount = 14;
+ fps = 15.0f;
+ lineWidth = 16;
+ alpha = 200;
+ fadeIn = false;
+ fadeOut = false;
+ fadeOutCounter = 0;
+ shell.setData(INFINITE_PANEL_KEY, this);
+
+ parent.addListener(SWT.Activate, new Listener() {
+
+ @Override
+ public void handleEvent(final Event e) {
+ if (shellHover != null && //
+ !shellHover.isDisposed() && !shellHover.isVisible()) {
+ shellHover.setVisible(true);
+ shellHover.setActive();
+ }
+ }
+ });
+ }
+
+ /**
+ * Starts the ticker.
+ */
+ public void start() {
+ if (parent.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ currentPosition = 0;
+ fadeIn = true;
+ fadeOut = false;
+ fadeOutCounter = 0;
+
+ if (defaultColor == null) {
+ defaultColor = SWTGraphicUtil.getDefaultColor(parent, 200, 200, 200);
+ }
+
+ if (selectionColor == null) {
+ selectionColor = parent.getDisplay().getSystemColor(SWT.COLOR_BLACK);
+ }
+
+ createShell();
+ createAndRunAnimatorThread();
+ }
+
+ /**
+ * Creates the shell.
+ */
+ private void createShell() {
+ shellHover = new Shell(parent, SWT.APPLICATION_MODAL | SWT.NO_TRIM | SWT.ON_TOP);
+ shellHover.setLayout(new FillLayout());
+ shellHover.setAlpha(0);
+
+ shellHover.addListener(SWT.KeyUp, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ event.doit = false;
+ }
+ });
+
+ shellHover.addListener(SWT.Deactivate, new Listener() {
+
+ @Override
+ public void handleEvent(final Event arg0) {
+ shellHover.setVisible(false);
+ }
+ });
+
+ shellHover.setBounds(shellHover.getDisplay().map(parent, null, parent.getClientArea()));
+
+ canvas = new Canvas(shellHover, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
+ canvas.addPaintListener(new PaintListener() {
+
+ @Override
+ public void paintControl(final PaintEvent e) {
+ InfiniteProgressPanel.this.paintCanvas(e);
+ }
+ });
+
+ shellHover.open();
+ }
+
+ /**
+ * Creates the and run animator thread.
+ */
+ private void createAndRunAnimatorThread() {
+ animatorThread = new Thread() {
+
+ /**
+ * @see java.lang.Thread#run()
+ */
+ @Override
+ public void run() {
+ while (!Thread.interrupted()) {
+ currentPosition = (currentPosition + 1) % barsCount;
+ if (fadeOut) {
+ fadeOutCounter++;
+ }
+ shellHover.getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ canvas.redraw();
+ }
+ });
+
+ try {
+ sleep(fadeOut ? 20 : (long) (1000 / fps));
+ } catch (final InterruptedException e) {
+ break;
+ }
+ }
+ }
+ };
+ animatorThread.start();
+ }
+
+ /**
+ * Paint the canvas that holds the ticker.
+ *
+ * @param e the e
+ */
+ private void paintCanvas(final PaintEvent e) {
+ // Paint the panel
+ final Rectangle clientArea = ((Canvas) e.widget).getClientArea();
+ final GC gc = e.gc;
+
+ handleFadeIn();
+ handleFadeOut();
+ drawBackground(clientArea, gc);
+ drawTicker(clientArea, gc);
+ drawText(clientArea, gc);
+
+ }
+
+ /**
+ * Handle the fade in effect of the hover shell.
+ */
+ private void handleFadeIn() {
+ if (fadeIn) {
+ if (currentPosition == NUMBER_OF_STEPS) {
+ fadeIn = false;
+ shellHover.setAlpha(alpha);
+ } else {
+ shellHover.setAlpha(currentPosition * alpha / NUMBER_OF_STEPS);
+ }
+ }
+ }
+
+ /**
+ * Handle the fade out effect of the hover shell.
+ */
+ private void handleFadeOut() {
+ if (fadeOut) {
+ if (fadeOutCounter >= NUMBER_OF_STEPS) {
+ if (animatorThread != null) {
+ animatorThread.interrupt();
+ animatorThread = null;
+ }
+ if (!shellHover.isDisposed()) {
+ shellHover.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!shellHover.isDisposed()) {
+ shellHover.dispose();
+ }
+ }
+ });
+ }
+ }
+ shellHover.setAlpha(255 - fadeOutCounter * alpha / NUMBER_OF_STEPS);
+ }
+ }
+
+ /**
+ * Draw the background of the panel.
+ *
+ * @param clientArea client area of the canvas
+ * @param gc GC on with the background is drawn
+ */
+ private void drawBackground(final Rectangle clientArea, final GC gc) {
+ gc.setBackground(shellHover.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ gc.fillRectangle(clientArea);
+ }
+
+ /**
+ * Draw the ticker.
+ *
+ * @param clientArea client area of the canvas
+ * @param gc GC on with the ticker is drawn
+ */
+ private void drawTicker(final Rectangle clientArea, final GC gc) {
+ final int centerX = clientArea.width / 2;
+ final int centerY = clientArea.height / 2;
+ final int maxRay = (int) (Math.min(clientArea.width, clientArea.height) * 0.6f) / 2;
+ final int minRay = (int) (maxRay * 0.5f);
+
+ double angle = Math.PI / 2;
+
+ gc.setLineCap(SWT.CAP_ROUND);
+ gc.setLineWidth(lineWidth);
+ gc.setAntialias(SWT.ON);
+
+ final double angleStep = 2 * Math.PI / barsCount;
+ for (int i = 0; i < barsCount; i++) {
+ if (i == currentPosition) {
+ gc.setForeground(selectionColor);
+ } else {
+ gc.setForeground(defaultColor);
+ }
+ gc.drawLine((int) (centerX + minRay * Math.cos(angle)), //
+ (int) (centerY - minRay * Math.sin(angle)), //
+ (int) (centerX + maxRay * Math.cos(angle)), //
+ (int) (centerY - maxRay * Math.sin(angle)));
+ angle -= angleStep;
+ }
+ }
+
+ /**
+ * Draw the text over the ticker.
+ *
+ * @param clientArea client area of the canvas
+ * @param gc GC on with the text is drawn
+ */
+ private void drawText(final Rectangle clientArea, final GC gc) {
+ if (text == null || "".equals(text)) {
+ return;
+ }
+
+ final Font font;
+ if (textFont == null) {
+ font = parent.getDisplay().getSystemFont();
+ } else {
+ font = textFont;
+ }
+
+ final Color color;
+ if (textColor == null) {
+ color = parent.getDisplay().getSystemColor(SWT.COLOR_BLACK);
+ } else {
+ color = textColor;
+ }
+
+ gc.setForeground(color);
+ gc.setFont(font);
+ gc.setTextAntialias(SWT.ON);
+ final Point textSize = gc.textExtent(text, SWT.DRAW_TRANSPARENT);
+ final int textWidth = textSize.x;
+ final int textHeight = textSize.y;
+
+ gc.drawString(text, (clientArea.width - textWidth) / 2, (clientArea.height - textHeight) / 2, true);
+
+ }
+
+ /**
+ * Stop the animation and dispose the panel.
+ */
+ public void stop() {
+ if (shellHover.isDisposed() || shellHover.getDisplay().isDisposed()) {
+ return;
+ }
+ fadeOut = true;
+ }
+
+ /**
+ * Returns the infinite progress panel for the shell. If no infinite panel
+ * has been declared, returns null.
+ *
+ * @param shell the shell for which we are trying to get the associated
+ * progess panel
+ * @return the progress panel associated to shell, or null if there is no
+ * progress panel
+ */
+ public static InfiniteProgressPanel getInfiniteProgressPanelFor(final Shell shell) {
+ if (shell == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ return null; // to satisfy SONAR
+ }
+
+ if (shell.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ return null; // to satisfy SONAR
+ }
+
+ if (shell.getDisplay().isDisposed()) {
+ SWT.error(SWT.ERROR_DEVICE_DISPOSED);
+ return null; // to satisfy SONAR
+ }
+
+ final InfiniteProgressPanel[] temp = new InfiniteProgressPanel[1];
+ shell.getDisplay().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ final Object data = shell.getData(INFINITE_PANEL_KEY);
+ if (data != null && data instanceof InfiniteProgressPanel) {
+ temp[0] = (InfiniteProgressPanel) data;
+ }
+ }
+ });
+
+ if (temp[0] == null) {
+ return new InfiniteProgressPanel(shell);
+ } else {
+ return temp[0];
+ }
+ }
+
+ /**
+ * Check if a shell has an associated progress panel.
+ *
+ * @param shell the shell
+ * @return <code>true</code> if the shell has an associated panel,
+ * <code>false</code> otherwise
+ */
+ public static boolean hasInfiniteProgressPanel(final Shell shell) {
+ return getInfiniteProgressPanelFor(shell) != null;
+ }
+
+ // ------------------------------------------------- Getters and Setters
+
+ /**
+ * Gets the alpha.
+ *
+ * @return the alpha value of the panel
+ */
+ public int getAlpha() {
+ return alpha;
+ }
+
+ /**
+ * Sets the alpha.
+ *
+ * @param alpha the alpha value of the panel, between 0 and 255
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the animation is running</li>
+ * </ul>
+ */
+ public void setAlpha(final int alpha) {
+ if (alpha < 0 || alpha > 255) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ checkIfAnimationIsRunning();
+ this.alpha = alpha;
+ }
+
+ /**
+ * Check if the animation is running.
+ */
+ private void checkIfAnimationIsRunning() {
+ if (animatorThread != null) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, "Can not change this value when an animation is running");
+ }
+ }
+
+ /**
+ * Gets the bars count.
+ *
+ * @return the number of bars displayed in the ticker
+ */
+ public int getBarsCount() {
+ return barsCount;
+ }
+
+ /**
+ * Sets the bars count.
+ *
+ * @param barsCount the number of bars displayed in the ticker
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the animation is running</li>
+ * </ul>
+ */
+ public void setBarsCount(final int barsCount) {
+ checkIfAnimationIsRunning();
+ this.barsCount = barsCount;
+ }
+
+ /**
+ * Gets the default color.
+ *
+ * @return the default color for the ticker's bars
+ */
+ public Color getDefaultColor() {
+ return defaultColor;
+ }
+
+ /**
+ * Sets the default color.
+ *
+ * @param defaultColor the new default color for the ticker's bars. Please
+ * notice that the previous color is disposed.
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the animation is running</li>
+ * </ul>
+ */
+ public void setDefaultColor(final Color defaultColor) {
+ checkIfAnimationIsRunning();
+ SWTGraphicUtil.safeDispose(this.defaultColor);
+ this.defaultColor = defaultColor;
+ }
+
+ /**
+ * Gets the fps.
+ *
+ * @return the number of frame per second for the animation
+ */
+ public float getFps() {
+ return fps;
+ }
+
+ /**
+ * Sets the fps.
+ *
+ * @param fps the new frame per second value
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the animation is running</li>
+ * </ul>
+ */
+ public void setFps(final float fps) {
+ checkIfAnimationIsRunning();
+ this.fps = fps;
+ }
+
+ /**
+ * Gets the line width.
+ *
+ * @return the line width of the bars that compose the ticker
+ */
+ public int getLineWidth() {
+ return lineWidth;
+ }
+
+ /**
+ * Sets the line width.
+ *
+ * @param lineWidth the line width of the bars that compose the ticker
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the animation is running</li>
+ * </ul>
+ */
+ public void setLineWidth(final int lineWidth) {
+ checkIfAnimationIsRunning();
+ this.lineWidth = lineWidth;
+ }
+
+ /**
+ * Gets the selection color.
+ *
+ * @return the selection color of the ticker's bars
+ */
+ public Color getSelectionColor() {
+ return selectionColor;
+ }
+
+ /**
+ * Sets the selection color.
+ *
+ * @param selectionColor the new selection color for the ticker's bars.
+ * Please notice that the previous color is disposed.
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the animation is running</li>
+ * </ul>
+ */
+ public void setSelectionColor(final Color selectionColor) {
+ checkIfAnimationIsRunning();
+ this.selectionColor = selectionColor;
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @return the displayed text
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Sets the text.
+ *
+ * @param text set the text to display
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the animation is running</li>
+ * </ul>
+ */
+ public void setText(final String text) {
+ checkIfAnimationIsRunning();
+ this.text = text;
+ }
+
+ /**
+ * Gets the text color.
+ *
+ * @return the text color
+ */
+ public Color getTextColor() {
+ return textColor;
+ }
+
+ /**
+ * Sets the text color.
+ *
+ * @param textColor the text color. Please notice that the previous color is
+ * disposed.
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the animation is running</li>
+ * </ul>
+ */
+ public void setTextColor(final Color textColor) {
+ checkIfAnimationIsRunning();
+ this.textColor = textColor;
+ }
+
+ /**
+ * Gets the text font.
+ *
+ * @return the text font
+ */
+ public Font getTextFont() {
+ return textFont;
+ }
+
+ /**
+ * Sets the text font.
+ *
+ * @param textFont the new text font. Please notice that the previous font
+ * set is disposed.
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the animation is running</li>
+ * </ul>
+ */
+ public void setTextFont(final Font textFont) {
+ checkIfAnimationIsRunning();
+ this.textFont = textFont;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DLItem.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DLItem.java
new file mode 100644
index 0000000..f294a37
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DLItem.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * 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.itemSelector;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.mihalis.opal.OpalItem;
+
+/**
+ * Instances of this class represents items manipulated by this DualList widget.
+ */
+public class DLItem extends OpalItem {
+
+ /**
+ * The Enum LAST_ACTION.
+ */
+ public enum LAST_ACTION {
+
+ /** The none. */
+ NONE,
+ /** The selection. */
+ SELECTION,
+ /** The deselection. */
+ DESELECTION
+ };
+
+ /** The last action. */
+ private LAST_ACTION lastAction;
+
+ /**
+ * Constructor.
+ *
+ * @param text the text displayed in the DualList widget for this item
+ */
+ public DLItem(final String text) {
+ this(text, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param text the text displayed in the DualList widget for this item
+ * @param image the image displayed in the DualList widget for this item
+ */
+ public DLItem(final String text, final Image image) {
+ this(text, image, (Font) null, (Color) null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param text the text displayed in the DualList widget for this item
+ * @param image the image displayed in the DualList widget for this item
+ * @param font the font displayed in the DualList widget for this item
+ * @param foregroundColor the foreground color displayed in the DualList
+ * widget for this item
+ */
+ public DLItem(final String text, final Image image, final Font font, final Color foregroundColor) {
+ this.setText(text);
+ this.setImage(image);
+ this.setFont(font);
+ this.setForeground(foregroundColor);
+ this.lastAction = LAST_ACTION.NONE;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param text the text displayed in the DualList widget for this item
+ * @param image the image displayed in the DualList widget for this item
+ * @param foregroundColor the foreground color displayed in the DualList
+ * widget for this item
+ * @param backgroundColor the background color displayed in the DualList
+ * widget for this item
+ */
+ public DLItem(final String text, final Image image, final Color foregroundColor, final Color backgroundColor) {
+ this.setText(text);
+ this.setImage(image);
+ this.setForeground(foregroundColor);
+ this.setBackground(backgroundColor);
+ this.lastAction = LAST_ACTION.NONE;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param text the text displayed in the DualList widget for this item
+ * @param image the image displayed in the DualList widget for this item
+ * @param font the font displayed in the DualList widget for this item
+ */
+ public DLItem(final String text, final Image image, final Font font) {
+ this(text, image, font, null);
+ }
+
+ /**
+ * Gets the height.
+ *
+ * @return the height
+ * @see org.mihalis.opal.OpalItem#getHeight()
+ */
+ @Override
+ public int getHeight() {
+ throw new UnsupportedOperationException("DLItem does not support this method");
+ }
+
+ /**
+ * Sets the height.
+ *
+ * @param height the new height
+ * @see org.mihalis.opal.OpalItem#setHeight(int)
+ */
+ @Override
+ public void setHeight(final int height) {
+ throw new UnsupportedOperationException("DLItem does not support this method");
+ }
+
+ /**
+ * Gets the last action.
+ *
+ * @return the last action (NONE, SELECTION, DESELECTION)
+ */
+ public LAST_ACTION getLastAction() {
+ return this.lastAction;
+ }
+
+ /**
+ * Sets the last action.
+ *
+ * @param lastAction the last action performed on this DLItem
+ */
+ public void setLastAction(final LAST_ACTION lastAction) {
+ this.lastAction = lastAction;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DualList.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DualList.java
new file mode 100644
index 0000000..94bfdbc
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/DualList.java
@@ -0,0 +1,1858 @@
+/*******************************************************************************
+ * 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.itemSelector;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+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.Event;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.mihalis.opal.itemSelector.DLItem.LAST_ACTION;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+import org.mihalis.opal.utils.SimpleSelectionAdapter;
+
+/**
+ * Instances of this class are controls that allow the user to select multiple
+ * elements.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ */
+
+public class DualList extends Composite {
+
+ /** The Constant DOUBLE_DOWN_IMAGE. */
+ private static final String DOUBLE_DOWN_IMAGE = "double_down.png";
+
+ /** The Constant DOUBLE_UP_IMAGE. */
+ private static final String DOUBLE_UP_IMAGE = "double_up.png";
+
+ /** The Constant DOUBLE_LEFT_IMAGE. */
+ private static final String DOUBLE_LEFT_IMAGE = "double_left.png";
+
+ /** The Constant DOUBLE_RIGHT_IMAGE. */
+ private static final String DOUBLE_RIGHT_IMAGE = "double_right.png";
+
+ /** The Constant ARROW_DOWN_IMAGE. */
+ private static final String ARROW_DOWN_IMAGE = "arrow_down.png";
+
+ /** The Constant ARROW_LEFT_IMAGE. */
+ private static final String ARROW_LEFT_IMAGE = "arrow_left.png";
+
+ /** The Constant ARROW_UP_IMAGE. */
+ private static final String ARROW_UP_IMAGE = "arrow_up.png";
+
+ /** The Constant ARROW_RIGHT_IMAGE. */
+ private static final String ARROW_RIGHT_IMAGE = "arrow_right.png";
+
+ /** The items. */
+ private final List<DLItem> items;
+
+ /** The selection. */
+ private final List<DLItem> selection;
+
+ /** The items table. */
+ private Table itemsTable;
+
+ /** The selection table. */
+ private Table selectionTable;
+
+ /** The selection listeners. */
+ private List<SelectionListener> selectionListeners;
+
+ /** The selection change listeners. */
+ private List<SelectionChangeListener> selectionChangeListeners;
+
+ /**
+ * 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 DualList(final Composite parent, final int style) {
+ super(parent, style);
+ items = new ArrayList<DLItem>();
+ selection = new ArrayList<DLItem>();
+
+ setLayout(new GridLayout(4, false));
+ createItemsTable();
+ createButtonSelectAll();
+ createSelectionTable();
+ createButtonMoveFirst();
+ createButtonSelect();
+ createButtonMoveUp();
+ createButtonDeselect();
+ createButtonMoveDown();
+ createButtonDeselectAll();
+ createButtonMoveLast();
+ }
+
+ /**
+ * Creates the items table.
+ */
+ private void createItemsTable() {
+ itemsTable = createTable();
+ itemsTable.addMouseListener(new MouseAdapter() {
+ /**
+ * @see org.eclipse.swt.events.MouseAdapter#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
+ */
+ @Override
+ public void mouseDoubleClick(final MouseEvent event) {
+ DualList.this.selectItem();
+ }
+ });
+ }
+
+ /**
+ * Creates the table.
+ *
+ * @return a table that will contain data
+ */
+ private Table createTable() {
+ final Table table = new Table(this, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.FULL_SELECTION);
+ table.setLinesVisible(false);
+ table.setHeaderVisible(false);
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true, 1, 4);
+ gd.widthHint = 200;
+ table.setLayoutData(gd);
+// new TableColumn(table, SWT.CENTER);
+// new TableColumn(table, SWT.LEFT);
+ table.setData(-1);
+ return table;
+ }
+
+ /**
+ * Creates the button select all.
+ */
+ private void createButtonSelectAll() {
+ final Button buttonSelectAll = createButton(DOUBLE_RIGHT_IMAGE, true, GridData.END);
+ buttonSelectAll.addSelectionListener(new SimpleSelectionAdapter() {
+ /**
+ * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void handle(final SelectionEvent e) {
+ DualList.this.selectAll();
+ }
+ });
+ }
+
+ /**
+ * Creates the selection table.
+ */
+ private void createSelectionTable() {
+ selectionTable = createTable();
+ selectionTable.addMouseListener(new MouseAdapter() {
+ /**
+ * @see org.eclipse.swt.events.MouseAdapter#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
+ */
+ @Override
+ public void mouseDoubleClick(final MouseEvent event) {
+ DualList.this.deselectItem();
+ }
+ });
+ }
+
+ /**
+ * Creates the button move first.
+ */
+ private void createButtonMoveFirst() {
+ final Button buttonMoveFirst = createButton(DOUBLE_UP_IMAGE, true, GridData.END);
+ buttonMoveFirst.addSelectionListener(new SimpleSelectionAdapter() {
+ /**
+ * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void handle(final SelectionEvent e) {
+ DualList.this.moveSelectionToFirstPosition();
+ }
+ });
+ }
+
+ /**
+ * Creates the button select.
+ */
+ private void createButtonSelect() {
+ final Button buttonSelect = createButton(ARROW_RIGHT_IMAGE, false, GridData.CENTER);
+ buttonSelect.addSelectionListener(new SimpleSelectionAdapter() {
+ /**
+ * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void handle(final SelectionEvent e) {
+ DualList.this.selectItem();
+ }
+ });
+ }
+
+ /**
+ * Creates the button move up.
+ */
+ private void createButtonMoveUp() {
+ final Button buttonMoveUp = createButton(ARROW_UP_IMAGE, false, GridData.CENTER);
+ buttonMoveUp.addSelectionListener(new SimpleSelectionAdapter() {
+ /**
+ * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void handle(final SelectionEvent e) {
+ DualList.this.moveUpItem();
+ }
+ });
+ }
+
+ /**
+ * Creates the button deselect.
+ */
+ private void createButtonDeselect() {
+ final Button buttonDeselect = createButton(ARROW_LEFT_IMAGE, false, GridData.CENTER);
+ buttonDeselect.addSelectionListener(new SimpleSelectionAdapter() {
+ /**
+ * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void handle(final SelectionEvent e) {
+ DualList.this.deselectItem();
+ }
+ });
+ }
+
+ /**
+ * Creates the button move down.
+ */
+ private void createButtonMoveDown() {
+ final Button buttonMoveDown = createButton(ARROW_DOWN_IMAGE, false, GridData.CENTER);
+ buttonMoveDown.addSelectionListener(new SimpleSelectionAdapter() {
+ /**
+ * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void handle(final SelectionEvent e) {
+ DualList.this.moveDownItem();
+ }
+ });
+ }
+
+ /**
+ * Creates the button deselect all.
+ */
+ private void createButtonDeselectAll() {
+ final Button buttonDeselectAll = createButton(DOUBLE_LEFT_IMAGE, false, GridData.BEGINNING);
+ buttonDeselectAll.addSelectionListener(new SimpleSelectionAdapter() {
+ /**
+ * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void handle(final SelectionEvent e) {
+ DualList.this.deselectAll();
+ }
+ });
+ }
+
+ /**
+ * Creates the button move last.
+ */
+ private void createButtonMoveLast() {
+ final Button buttonMoveLast = createButton(DOUBLE_DOWN_IMAGE, true, GridData.BEGINNING);
+ buttonMoveLast.addSelectionListener(new SimpleSelectionAdapter() {
+ /**
+ * @see org.mihalis.opal.utils.SimpleSelectionAdapter#handle(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void handle(final SelectionEvent e) {
+ DualList.this.moveSelectionToLastPosition();
+ }
+ });
+ }
+
+ /**
+ * Create a button.
+ *
+ * @param fileName file name of the icon
+ * @param verticalExpand if <code>true</code>, the button will take all the
+ * available space vertically
+ * @param alignment button alignment
+ * @return a new button
+ */
+ private Button createButton(final String fileName, final boolean verticalExpand, final int alignment) {
+ final Button button = new Button(this, SWT.PUSH);
+ final ClassLoader loader = org.mihalis.opal.itemSelector.DualList.class.getClassLoader();
+ final Image image = new Image(getDisplay(), loader.getResourceAsStream("images/" + fileName));
+ button.setImage(image);
+ button.setLayoutData(new GridData(GridData.CENTER, alignment, false, verticalExpand));
+ SWTGraphicUtil.addDisposer(button, image);
+ return button;
+ }
+
+ /**
+ * Adds the argument to the end of the receiver's list.
+ *
+ * @param item the new item
+ * @see #add(DLItem,int)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item 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 add(final DLItem item) {
+ checkWidget();
+ if (item == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ items.add(item);
+ redrawTables();
+ }
+
+ /**
+ * Adds the argument to the receiver's list at the given zero-relative
+ * index.
+ * <p>
+ * Note: To add an item at the end of the list, use the result of calling
+ * <code>getItemCount()</code> as the index or use <code>add(DLItem)</code>.
+ * </p>
+ *
+ * @param item the new item
+ * @param index the index for the item
+ * @see #add(String)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_RANGE - if the index is not between 0
+ * and the number of elements in the list (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 void add(final DLItem item, final int index) {
+ checkWidget();
+ if (item == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (index < 0 || index >= items.size()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ items.add(index, item);
+ redrawTables();
+ }
+
+ /**
+ * 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
+ * @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);
+ }
+ if (selectionListeners == null) {
+ selectionListeners = new ArrayList<SelectionListener>();
+ }
+ selectionListeners.add(listener);
+ }
+
+ /**
+ * 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();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (selectionListeners == null) {
+ return;
+ }
+ selectionListeners.remove(listener);
+ }
+
+ /**
+ * 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>SelectionChangeListener</code> interface.
+ *
+ * @param listener the listener which should be notified
+ * @see SelectionChangeListener
+ * @see #removeSelectionChangeListener
+ * @see SelectionChangeEvent
+ * @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 addSelectionChangeListener(final SelectionChangeListener listener) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (selectionChangeListeners == null) {
+ selectionChangeListeners = new ArrayList<SelectionChangeListener>();
+ }
+ selectionChangeListeners.add(listener);
+ }
+
+ /**
+ * 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 SelectionChangeListener
+ * @see #addSelectionChangeListener
+ * @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 removeSelectionChangeListener(final SelectionChangeListener listener) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (selectionChangeListeners == null) {
+ return;
+ }
+ selectionChangeListeners.remove(listener);
+ }
+
+ /**
+ * Deselects the item at the given zero-relative index in the receiver. If
+ * the item at the index was already deselected, it remains deselected.
+ * Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to deselect
+ *
+ * @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 deselect(final int index) {
+ deselect(index, true);
+ }
+
+ /**
+ * Deselects the item at the given zero-relative index in the receiver. If
+ * the item at the index was already deselected, it remains deselected.
+ * Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to deselect
+ *
+ * @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 deselectDoNotFireEvent(final int index) {
+ deselect(index, false);
+ }
+
+ /**
+ * Deselects the item at the given zero-relative index in the receiver. If
+ * the item at the index was already deselected, it remains deselected.
+ * Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to deselect
+ * @param shouldFireEvents the should fire events
+ * @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>
+ */
+ private void deselect(final int index, final boolean shouldFireEvents) {
+ checkWidget();
+ if (index < 0 || index >= items.size()) {
+ return;
+ }
+ final DLItem item = selection.remove(index);
+ if (shouldFireEvents) {
+ fireSelectionEvent(item);
+ }
+
+ final List<DLItem> deselectedItems = new ArrayList<DLItem>();
+ item.setLastAction(LAST_ACTION.DESELECTION);
+ deselectedItems.add(item);
+ if (shouldFireEvents) {
+ fireSelectionChangeEvent(deselectedItems);
+ }
+ redrawTables();
+ }
+
+ /**
+ * Deselects the items at the given zero-relative indices in the receiver.
+ * If the item at the given zero-relative index in the receiver is selected,
+ * it is deselected. If the item at the index was not selected, it remains
+ * deselected. Indices that are out of range and duplicate indices are
+ * ignored.
+ *
+ * @param indices the array of indices for the items to deselect
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the set of indices 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 deselect(final int[] indices) {
+ deselect(indices, true);
+ }
+
+ /**
+ * Deselects the items at the given zero-relative indices in the receiver.
+ * If the item at the given zero-relative index in the receiver is selected,
+ * it is deselected. If the item at the index was not selected, it remains
+ * deselected. Indices that are out of range and duplicate indices are
+ * ignored.
+ *
+ * @param indices the array of indices for the items to deselect
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the set of indices 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 deselectDoNotFireEvent(final int[] indices) {
+ deselect(indices, false);
+ }
+
+ /**
+ * Deselects the items at the given zero-relative indices in the receiver.
+ * If the item at the given zero-relative index in the receiver is selected,
+ * it is deselected. If the item at the index was not selected, it remains
+ * deselected. Indices that are out of range and duplicate indices are
+ * ignored.
+ *
+ * @param indices the array of indices for the items to deselect
+ * @param shouldFireEvents the should fire events
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the set of indices 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>
+ */
+ private void deselect(final int[] indices, final boolean shouldFireEvents) {
+ checkWidget();
+ if (indices == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ final List<DLItem> toBeRemoved = new ArrayList<DLItem>();
+
+ for (final int index : indices) {
+ if (index < 0 || index >= items.size()) {
+ continue;
+ }
+ toBeRemoved.add(selection.get(index));
+ }
+
+ for (final DLItem item : toBeRemoved) {
+ selection.remove(item);
+ if (shouldFireEvents) {
+ fireSelectionEvent(item);
+ }
+ }
+ if (shouldFireEvents) {
+ fireSelectionChangeEvent(toBeRemoved);
+ }
+
+ toBeRemoved.clear();
+ redrawTables();
+ }
+
+ /**
+ * Deselects the items at the given zero-relative indices in the receiver.
+ * If the item at the given zero-relative index in the receiver is selected,
+ * it is deselected. If the item at the index was not selected, it remains
+ * deselected. The range of the indices is inclusive. Indices that are out
+ * of range are ignored.
+ *
+ * @param start the start index of the items to deselect
+ * @param end the end index of the items to deselect
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_INVALID_RANGE - if start is greater than end
+ * </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 deselect(final int start, final int end) {
+ deselect(start, end, true);
+ }
+
+ /**
+ * Deselects the items at the given zero-relative indices in the receiver.
+ * If the item at the given zero-relative index in the receiver is selected,
+ * it is deselected. If the item at the index was not selected, it remains
+ * deselected. The range of the indices is inclusive. Indices that are out
+ * of range are ignored.
+ *
+ * @param start the start index of the items to deselect
+ * @param end the end index of the items to deselect
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_INVALID_RANGE - if start is greater than end
+ * </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 deselectDoNotFireEvent(final int start, final int end) {
+ deselect(start, end, false);
+ }
+
+ /**
+ * Deselect.
+ *
+ * @param start the start
+ * @param end the end
+ * @param shouldFireEvents the should fire events
+ */
+ private void deselect(final int start, final int end, final boolean shouldFireEvents) {
+ checkWidget();
+ if (start > end) {
+ SWT.error(SWT.ERROR_INVALID_RANGE);
+ }
+ final List<DLItem> toBeRemoved = new ArrayList<DLItem>();
+
+ for (int index = start; index <= end; index++) {
+ if (index < 0 || index >= items.size()) {
+ continue;
+ }
+ toBeRemoved.add(selection.get(index));
+ }
+
+ for (final DLItem item : toBeRemoved) {
+ selection.remove(item);
+ if (shouldFireEvents) {
+ fireSelectionEvent(item);
+ }
+ }
+ if (shouldFireEvents) {
+ fireSelectionChangeEvent(toBeRemoved);
+ }
+ toBeRemoved.clear();
+ redrawTables();
+ }
+
+ /**
+ * Deselects all selected 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 void deselectAll() {
+ deselectAll(true);
+ }
+
+ /**
+ * Deselects all selected 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 void deselectAllDoNotFireEvent() {
+ deselectAll(false);
+ }
+
+ /**
+ * Deselects all selected items in the receiver.
+ *
+ * @param shouldFireEvents the should fire events
+ * @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 deselectAll(final boolean shouldFireEvents) {
+ checkWidget();
+ items.addAll(selection);
+
+ final List<DLItem> deselectedItems = new ArrayList<DLItem>();
+ for (final DLItem item : selection) {
+ item.setLastAction(LAST_ACTION.DESELECTION);
+ deselectedItems.add(item);
+ if (shouldFireEvents) {
+ fireSelectionEvent(item);
+ }
+ }
+ fireSelectionChangeEvent(deselectedItems);
+
+ selection.clear();
+ redrawTables();
+ }
+
+ /**
+ * 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 DLItem getItem(final int index) {
+ checkWidget();
+ if (index < 0 || index >= items.size()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ return items.get(index);
+ }
+
+ /**
+ * 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 items.size();
+ }
+
+ /**
+ * Returns a (possibly empty) array of <code>DLItem</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's list
+ *
+ * @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 DLItem[] getItems() {
+ checkWidget();
+ return items.toArray(new DLItem[items.size()]);
+ }
+
+ /**
+ * Returns a (possibly empty) list of <code>DLItem</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's list
+ *
+ * @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 List<DLItem> getItemsAsList() {
+ checkWidget();
+ return new ArrayList<DLItem>(items);
+ }
+
+ /**
+ * Returns an array of <code>DLItem</code>s that are currently selected in
+ * the receiver. An empty array indicates that no items are selected.
+ * <p>
+ * Note: This is not the actual structure used by the receiver to maintain
+ * its selection, so modifying the array will not affect the receiver.
+ * </p>
+ *
+ * @return an array representing 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 DLItem[] getSelection() {
+ checkWidget();
+ return selection.toArray(new DLItem[items.size()]);
+ }
+
+ /**
+ * Returns a list of <code>DLItem</code>s that are currently selected in the
+ * receiver. An empty array indicates that no items are selected.
+ * <p>
+ * Note: This is not the actual structure used by the receiver to maintain
+ * its selection, so modifying the array will not affect the receiver.
+ * </p>
+ *
+ * @return an array representing 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 List<DLItem> getSelectionAsList() {
+ checkWidget();
+ return new ArrayList<DLItem>(selection);
+ }
+
+ /**
+ * Returns the number of selected items contained in the receiver.
+ *
+ * @return the number of selected 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 getSelectionCount() {
+ checkWidget();
+ return selection.size();
+ }
+
+ /**
+ * Removes the item from the receiver at the given zero-relative index.
+ *
+ * @param index the index for the item
+ *
+ * @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 void remove(final int index) {
+ checkWidget();
+ if (index < 0 || index >= items.size()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ items.remove(index);
+ redrawTables();
+ }
+
+ /**
+ * Removes the items from the receiver at the given zero-relative indices.
+ *
+ * @param indices the array of indices of the items
+ *
+ * @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>
+ * <li>ERROR_NULL_ARGUMENT - if the indices array 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 remove(final int[] indices) {
+ checkWidget();
+ for (final int index : indices) {
+ if (index < 0 || index >= items.size()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ items.remove(index);
+ }
+ redrawTables();
+ }
+
+ /**
+ * Removes the items from the receiver which are between the given
+ * zero-relative start and end indices (inclusive).
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_INVALID_RANGE - if either the start or end are
+ * not between 0 and the number of elements in the list minus
+ * 1 (inclusive) or if start>end</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 remove(final int start, final int end) {
+ checkWidget();
+ if (start > end) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ for (int index = start; index < end; index++) {
+ if (index < 0 || index >= items.size()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ items.remove(index);
+ }
+ redrawTables();
+ }
+
+ /**
+ * Searches the receiver's list starting at the first item until an item is
+ * found that is equal to the argument, and removes that item from the list.
+ *
+ * @param item the item to remove
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the item is not found in
+ * the list</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 remove(final DLItem item) {
+ checkWidget();
+ if (item == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (!items.contains(item)) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ items.remove(item);
+ redrawTables();
+ }
+
+ /**
+ * Removes all of the items from the receiver.
+ * <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 removeAll() {
+ checkWidget();
+ items.clear();
+ redrawTables();
+ }
+
+ /**
+ * Selects the item at the given zero-relative index in the receiver's list.
+ * If the item at the index was already selected, it remains selected.
+ * Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @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 int index) {
+ select(index, true);
+ }
+
+ /**
+ * Selects the item at the given zero-relative index in the receiver's list.
+ * If the item at the index was already selected, it remains selected.
+ * Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @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 selectDoNotFireEvent(final int index) {
+ select(index, false);
+ }
+
+ /**
+ * Select.
+ *
+ * @param index the index
+ * @param shouldFireEvents the should fire events
+ */
+ private void select(final int index, final boolean shouldFireEvents) {
+ checkWidget();
+ if (index < 0 || index >= items.size()) {
+ return;
+ }
+ final List<DLItem> selectedItems = new ArrayList<DLItem>();
+ final DLItem item = items.get(index);
+ item.setLastAction(LAST_ACTION.SELECTION);
+ selectedItems.add(item);
+ selection.add(item);
+
+ if (shouldFireEvents) {
+ fireSelectionEvent(item);
+ fireSelectionChangeEvent(selectedItems);
+ }
+
+ redrawTables();
+ }
+
+ /**
+ * Selects the items at the given zero-relative indices in the receiver. The
+ * current selection is not cleared before the new items are selected.
+ * <p>
+ * If the item at a given index is not selected, it is selected. If the item
+ * at a given index was already selected, it remains selected. Indices that
+ * are out of range and duplicate indices are ignored. If the receiver is
+ * single-select and multiple indices are specified, then all indices are
+ * ignored.
+ *
+ * @param indices the array of indices for the items to select
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of indices 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 select(final int[] indices) {
+ select(indices, true);
+ }
+
+ /**
+ * Selects the items at the given zero-relative indices in the receiver. The
+ * current selection is not cleared before the new items are selected.
+ * <p>
+ * If the item at a given index is not selected, it is selected. If the item
+ * at a given index was already selected, it remains selected. Indices that
+ * are out of range and duplicate indices are ignored. If the receiver is
+ * single-select and multiple indices are specified, then all indices are
+ * ignored.
+ *
+ * @param indices the array of indices for the items to select
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the array of indices 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 selectDoNotFireEvent(final int[] indices) {
+ select(indices, false);
+ }
+
+ /**
+ * Select.
+ *
+ * @param indices the indices
+ * @param shouldFireEvents the should fire events
+ */
+ private void select(final int[] indices, final boolean shouldFireEvents) {
+ checkWidget();
+ if (indices == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ final List<DLItem> selectedItems = new ArrayList<DLItem>();
+ for (final int index : indices) {
+ if (index < 0 || index >= items.size()) {
+ continue;
+ }
+ final DLItem item = items.get(index);
+ item.setLastAction(LAST_ACTION.SELECTION);
+ selectedItems.add(item);
+
+ selection.add(item);
+ if (shouldFireEvents) {
+ fireSelectionEvent(item);
+ }
+ }
+ if (shouldFireEvents) {
+ fireSelectionChangeEvent(selectedItems);
+ }
+ redrawTables();
+ }
+
+ /**
+ * Selects the items in the range specified by the given zero-relative
+ * indices in the receiver. The range of indices is inclusive. The current
+ * selection is not cleared before the new items are selected.
+ * <p>
+ * If an item in the given range is not selected, it is selected. If an item
+ * in the given range was already selected, it remains selected. Indices
+ * that are out of range are ignored and no items will be selected if start
+ * is greater than end. If the receiver is single-select and there is more
+ * than one item in the given range, then all indices are ignored.
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ * @see List#setSelection(int,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>
+ */
+ public void select(final int start, final int end) {
+ select(start, end, true);
+ }
+
+ /**
+ * Selects the items in the range specified by the given zero-relative
+ * indices in the receiver. The range of indices is inclusive. The current
+ * selection is not cleared before the new items are selected.
+ * <p>
+ * If an item in the given range is not selected, it is selected. If an item
+ * in the given range was already selected, it remains selected. Indices
+ * that are out of range are ignored and no items will be selected if start
+ * is greater than end. If the receiver is single-select and there is more
+ * than one item in the given range, then all indices are ignored.
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ * @see List#setSelection(int,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>
+ */
+ public void selectDoNotFireEvent(final int start, final int end) {
+ select(start, end, false);
+ }
+
+ /**
+ * Select.
+ *
+ * @param start the start
+ * @param end the end
+ * @param shouldFireEvents the should fire events
+ */
+ private void select(final int start, final int end, final boolean shouldFireEvents) {
+ checkWidget();
+ if (start > end) {
+ SWT.error(SWT.ERROR_INVALID_RANGE);
+ }
+ final List<DLItem> selectedItems = new ArrayList<DLItem>();
+ for (int index = start; index <= end; index++) {
+ if (index < 0 || index >= items.size()) {
+ continue;
+ }
+ final DLItem item = items.get(index);
+ item.setLastAction(LAST_ACTION.SELECTION);
+ selectedItems.add(item);
+ selection.add(item);
+ if (shouldFireEvents) {
+ fireSelectionEvent(item);
+ }
+ }
+ if (shouldFireEvents) {
+ fireSelectionChangeEvent(selectedItems);
+ }
+ redrawTables();
+ }
+
+ /**
+ * Selects all of the items in the receiver.
+ * <p>
+ * If the receiver is single-select, do nothing.
+ *
+ * @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 selectAll() {
+ selectAll(true);
+ }
+
+ /**
+ * Selects all of the items in the receiver.
+ * <p>
+ * If the receiver is single-select, do nothing.
+ *
+ * @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 selectAllDoNotFireEvent() {
+ selectAll(false);
+ }
+
+ /**
+ * Select all.
+ *
+ * @param shouldFireEvents the should fire events
+ */
+ private void selectAll(final boolean shouldFireEvents) {
+ checkWidget();
+ selection.addAll(items);
+ if (shouldFireEvents) {
+ for (final DLItem item : items) {
+ fireSelectionEvent(item);
+ }
+ }
+
+ if (shouldFireEvents) {
+ final List<DLItem> selectedItems = new ArrayList<DLItem>();
+ for (final DLItem item : items) {
+ item.setLastAction(LAST_ACTION.SELECTION);
+ selectedItems.add(item);
+ }
+ fireSelectionChangeEvent(selectedItems);
+ }
+ items.clear();
+ redrawTables();
+ }
+
+ /**
+ * Sets the bounds.
+ *
+ * @param x the x
+ * @param y the y
+ * @param width the width
+ * @param height the height
+ * @see org.eclipse.swt.widgets.Control#setBounds(int, int, int, int)
+ */
+ @Override
+ public void setBounds(final int x, final int y, final int width, final int height) {
+ super.setBounds(x, y, width, height);
+ final boolean itemsContainImage = itemsContainImage();
+ final Point itemsTableDefaultSize = itemsTable.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+ final Point selectionTableDefaultSize = selectionTable.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+
+ int itemsTableSize = itemsTable.getSize().x;
+ if (itemsTableDefaultSize.y > itemsTable.getSize().y) {
+ itemsTableSize -= itemsTable.getVerticalBar().getSize().x;
+ }
+
+ int selectionTableSize = selectionTable.getSize().x;
+ if (selectionTableDefaultSize.y > selectionTable.getSize().y) {
+ selectionTableSize -= selectionTable.getVerticalBar().getSize().x;
+ }
+
+ if (itemsContainImage) {
+ itemsTable.getColumn(0).pack();
+ itemsTable.getColumn(1).setWidth(itemsTableSize - itemsTable.getColumn(0).getWidth());
+
+ selectionTable.getColumn(0).pack();
+ selectionTable.getColumn(1).setWidth(selectionTableSize - selectionTable.getColumn(0).getWidth());
+
+ } else {
+ itemsTable.getColumn(0).setWidth(itemsTableSize);
+ selectionTable.getColumn(0).setWidth(selectionTableSize);
+ }
+
+ itemsTable.getColumn(0).pack();
+ selectionTable.getColumn(0).pack();
+ }
+
+ /**
+ * Items contain image.
+ *
+ * @return <code>true</code> if any item contains an image
+ */
+ private boolean itemsContainImage() {
+ for (final DLItem item : items) {
+ if (item.getImage() != null) {
+ return true;
+ }
+ }
+
+ for (final DLItem item : selection) {
+ if (item.getImage() != null) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Sets the item in the receiver's list at the given zero-relative index to
+ * the item argument.
+ *
+ * @param index the index for the item
+ * @param item the new item
+ *
+ * @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>
+ * <li>ERROR_NULL_ARGUMENT - if the item 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 setItem(final int index, final DLItem item) {
+ checkWidget();
+ if (item == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (index < 0 || index >= items.size()) {
+ SWT.error(SWT.ERROR_INVALID_RANGE);
+ }
+ items.set(index, item);
+ redrawTables();
+ }
+
+ /**
+ * Sets the receiver's items to be the given array of items.
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if an item in the items array
+ * 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 setItems(final DLItem[] items) {
+ checkWidget();
+ if (items == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ final List<DLItem> temp = new ArrayList<DLItem>();
+ for (final DLItem item : items) {
+ if (item == null) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ temp.add(item);
+ }
+ this.items.clear();
+ this.items.addAll(temp);
+ redrawTables();
+ }
+
+ /**
+ * Sets the receiver's items to be the given list of items.
+ *
+ * @param items the list of items
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the items list is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if an item in the items list
+ * 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 setItems(final List<DLItem> items) {
+ checkWidget();
+ checkWidget();
+ if (items == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ final List<DLItem> temp = new ArrayList<DLItem>();
+ for (final DLItem item : items) {
+ if (item == null) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ temp.add(item);
+ }
+ this.items.clear();
+ this.items.addAll(temp);
+ redrawTables();
+ }
+
+ /**
+ * Redraws all tables that compose this widget.
+ */
+ private void redrawTables() {
+ setRedraw(false);
+ redrawTable(itemsTable, false);
+ redrawTable(selectionTable, true);
+ setRedraw(true);
+ this.setBounds(getBounds());
+ }
+
+ /**
+ * Redraw a given table.
+ *
+ * @param table table to be redrawned
+ * @param isSelected if <code>true</code>, fill the table with the
+ * selection. Otherwise, fill the table with the unselected
+ * items.
+ */
+ private void redrawTable(final Table table, final boolean isSelected) {
+ clean(table);
+ fillData(table, isSelected ? selection : items);
+ }
+
+ /**
+ * Cleans the content of a table.
+ *
+ * @param table table to be emptied
+ */
+ private void clean(final Table table) {
+ if (table == null) {
+ return;
+ }
+
+ for (final TableItem item : table.getItems()) {
+ item.dispose();
+ }
+ }
+
+ /**
+ * Fill a table with data.
+ *
+ * @param table table to be filled
+ * @param listOfData list of data
+ */
+ private void fillData(final Table table, final List<DLItem> listOfData) {
+ final boolean itemsContainImage = itemsContainImage();
+ for (final DLItem item : listOfData) {
+ final TableItem tableItem = new TableItem(table, SWT.NONE);
+ tableItem.setData(item);
+
+ if (item.getBackground() != null) {
+ tableItem.setBackground(item.getBackground());
+ }
+
+ if (item.getForeground() != null) {
+ tableItem.setForeground(item.getForeground());
+ }
+
+ if (item.getImage() != null) {
+ tableItem.setImage(0, item.getImage());
+ }
+
+ if (item.getFont() != null) {
+ tableItem.setFont(item.getFont());
+ }
+ final int textColumn = itemsContainImage ? 1 : 0;
+ tableItem.setText(textColumn, item.getText());
+ }
+ }
+
+ /**
+ * Move the selected item to the first position.
+ */
+ protected void moveSelectionToFirstPosition() {
+ if (selectionTable.getSelectionCount() == 0) {
+ return;
+ }
+
+ int index = 0;
+ for (final TableItem tableItem : selectionTable.getSelection()) {
+ final DLItem item = (DLItem) tableItem.getData();
+ selection.remove(item);
+ selection.add(index++, item);
+ }
+
+ redrawTables();
+ selectionTable.select(0, index - 1);
+ selectionTable.forceFocus();
+ }
+
+ /**
+ * Select a given item.
+ */
+ protected void selectItem() {
+ if (itemsTable.getSelectionCount() == 0) {
+ return;
+ }
+ final List<DLItem> selectedItems = new ArrayList<DLItem>();
+ for (final TableItem tableItem : itemsTable.getSelection()) {
+ final DLItem item = (DLItem) tableItem.getData();
+ item.setLastAction(LAST_ACTION.SELECTION);
+ selectedItems.add(item);
+ selection.add(item);
+ items.remove(item);
+ fireSelectionEvent(item);
+ }
+ fireSelectionChangeEvent(selectedItems);
+
+ redrawTables();
+ }
+
+ /**
+ * Move the selected item up.
+ */
+ protected void moveUpItem() {
+ if (selectionTable.getSelectionCount() == 0) {
+ return;
+ }
+
+ for (final int index : selectionTable.getSelectionIndices()) {
+ if (index == 0) {
+ selectionTable.forceFocus();
+ return;
+ }
+ }
+
+ final int[] newSelection = new int[selectionTable.getSelectionCount()];
+ int newSelectionIndex = 0;
+ for (final TableItem tableItem : selectionTable.getSelection()) {
+ final int position = selection.indexOf(tableItem.getData());
+ swap(position, position - 1);
+ newSelection[newSelectionIndex++] = position - 1;
+ }
+
+ redrawTables();
+ selectionTable.select(newSelection);
+ selectionTable.forceFocus();
+ }
+
+ /**
+ * Deselect a given item.
+ */
+ protected void deselectItem() {
+ if (selectionTable.getSelectionCount() == 0) {
+ return;
+ }
+ final List<DLItem> deselectedItems = new ArrayList<DLItem>();
+ for (final TableItem tableItem : selectionTable.getSelection()) {
+ final DLItem item = (DLItem) tableItem.getData();
+ item.setLastAction(LAST_ACTION.DESELECTION);
+ deselectedItems.add(item);
+ items.add(item);
+ selection.remove(item);
+ fireSelectionEvent(item);
+ }
+ fireSelectionChangeEvent(deselectedItems);
+ redrawTables();
+ }
+
+ /**
+ * Move the selected item down.
+ */
+ protected void moveDownItem() {
+ if (selectionTable.getSelectionCount() == 0) {
+ return;
+ }
+
+ for (final int index : selectionTable.getSelectionIndices()) {
+ if (index == selectionTable.getItemCount() - 1) {
+ selectionTable.forceFocus();
+ return;
+ }
+ }
+
+ final int[] newSelection = new int[selectionTable.getSelectionCount()];
+ int newSelectionIndex = 0;
+ for (final TableItem tableItem : selectionTable.getSelection()) {
+ final int position = selection.indexOf(tableItem.getData());
+ swap(position, position + 1);
+ newSelection[newSelectionIndex++] = position + 1;
+ }
+
+ redrawTables();
+ selectionTable.select(newSelection);
+ selectionTable.forceFocus();
+ }
+
+ /**
+ * Swap 2 items.
+ *
+ * @param first position of the first item to swap
+ * @param second position of the second item to swap
+ */
+ private void swap(final int first, final int second) {
+ final DLItem temp = selection.get(first);
+ selection.set(first, selection.get(second));
+ selection.set(second, temp);
+ }
+
+ /**
+ * Move the selected item to the last position.
+ */
+ protected void moveSelectionToLastPosition() {
+ if (selectionTable.getSelectionCount() == 0) {
+ return;
+ }
+
+ final int numberOfSelectedElements = selectionTable.getSelectionCount();
+ for (final TableItem tableItem : selectionTable.getSelection()) {
+ final DLItem item = (DLItem) tableItem.getData();
+ selection.remove(item);
+ selection.add(item);
+ }
+
+ redrawTables();
+ final int numberOfElements = selectionTable.getItemCount();
+ selectionTable.select(numberOfElements - numberOfSelectedElements, numberOfElements - 1);
+ selectionTable.forceFocus();
+ }
+
+ /**
+ * Call all selection listeners.
+ *
+ * @param item selected item
+ */
+ private void fireSelectionEvent(final DLItem item) {
+ if (selectionListeners == null) {
+ return;
+ }
+
+ final Event event = new Event();
+ event.button = 1;
+ event.display = getDisplay();
+ event.item = null;
+ event.widget = this;
+ event.data = item;
+ final SelectionEvent selectionEvent = new SelectionEvent(event);
+
+ for (final SelectionListener listener : selectionListeners) {
+ listener.widgetSelected(selectionEvent);
+ }
+ }
+
+ /**
+ * Fire selection change event.
+ *
+ * @param items the items
+ */
+ private void fireSelectionChangeEvent(final List<DLItem> items) {
+ if (selectionChangeListeners == null) {
+ return;
+ }
+
+ final Event event = new Event();
+ event.button = 1;
+ event.display = getDisplay();
+ event.item = null;
+ event.widget = this;
+ final SelectionChangeEvent selectionChangeEvent = new SelectionChangeEvent(event);
+ selectionChangeEvent.setItems(items);
+
+ for (final SelectionChangeListener listener : selectionChangeListeners) {
+ listener.widgetSelected(selectionChangeEvent);
+ }
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/SelectionChangeEvent.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/SelectionChangeEvent.java
new file mode 100644
index 0000000..058186f
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/SelectionChangeEvent.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.itemSelector;
+
+import java.util.List;
+
+import org.eclipse.swt.events.TypedEvent;
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * Instances of this class are sent as a result of
+ * DualList being selected.
+ *
+ * @see SelectionChangeListener
+ */
+public class SelectionChangeEvent extends TypedEvent {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -7164363995093867940L;
+
+ /**
+ * The items that were selected.
+ */
+ private List<DLItem> items; // NOSONAR - SONAR demands transient or serializable!
+
+ /**
+ * A flag indicating whether the operation should be allowed.
+ * Setting this field to <code>false</code> will cancel the
+ * operation, depending on the widget.
+ */
+ public boolean doit;
+
+ /**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+ public SelectionChangeEvent(final Event e) {
+ super(e);
+ }
+
+ /**
+ * Gets the items that were selected.
+ *
+ * @return the list of items
+ */
+ public List<DLItem> getItems() {
+ return this.items;
+ }
+
+ /**
+ * Sets the items that were selected.
+ *
+ * @param items the list of items to set
+ */
+ public void setItems(final List<DLItem> items) {
+ this.items = items;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/SelectionChangeListener.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/SelectionChangeListener.java
new file mode 100644
index 0000000..f5af7cd
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/itemSelector/SelectionChangeListener.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.itemSelector;
+
+import org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * Classes which implement this interface provide methods
+ * that deal with the events that are generated when selection
+ * occurs in a control.
+ * <p>
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control using the
+ * <code>addSelectionChangeListener</code> method and removed using
+ * the <code>removeSelectionChangeListener</code> method. When
+ * selection occurs in a control the appropriate method
+ * will be invoked.
+ * </p>
+ *
+ * @see SelectionChangeEvent
+ */
+public interface SelectionChangeListener extends SWTEventListener {
+
+ /**
+ * Sent when selection occurs in the control.
+ *
+ * @param e an event containing information about the selection
+ */
+ public void widgetSelected(SelectionChangeEvent e);
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/Launcher.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/Launcher.java
new file mode 100644
index 0000000..692a07e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/Launcher.java
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * 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.launcher;
+
+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.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.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are a launcher composed of buttons. When one clicks
+ * on the button, an animation is started and a selection event is fired
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ */
+public class Launcher extends Composite {
+
+ /** The items. */
+ private final List<LauncherItem> items;
+
+ /** The selection listeners. */
+ private final List<SelectionListener> selectionListeners;
+
+ /** The need redraw. */
+ private boolean needRedraw;
+
+ /** The selection. */
+ private int selection = -1;
+
+ /**
+ * 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 Launcher(final Composite parent, final int style) {
+ super(parent, style | SWT.BORDER);
+ this.items = new ArrayList<LauncherItem>();
+ this.selectionListeners = new ArrayList<SelectionListener>();
+ this.needRedraw = true;
+ setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+
+ this.addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ drawLauncher();
+ }
+ });
+
+ this.addListener(SWT.KeyUp, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ handleKeyPressedEvent(event);
+ }
+ });
+ }
+
+ /**
+ * Draw the launcher.
+ */
+ private void drawLauncher() {
+ if (!this.needRedraw) {
+ return;
+ }
+
+ disposePreviousContent();
+ createButtons();
+ pack();
+
+ this.needRedraw = false;
+ }
+
+ /**
+ * Dispose the content before a redraw.
+ */
+ private void disposePreviousContent() {
+ for (final Control c : this.getChildren()) {
+ c.dispose();
+ }
+ }
+
+ /**
+ * Create the buttons that will compose the launcher.
+ */
+ private void createButtons() {
+ final GridLayout gridLayout = new GridLayout(this.items.size() / 2, true);
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
+ this.setLayout(gridLayout);
+ for (final LauncherItem item : this.items) {
+ createItem(item);
+ }
+ }
+
+ /**
+ * Creates the item.
+ *
+ * @param item the item
+ */
+ private void createItem(final LauncherItem item) {
+ final LauncherLabel label = createLauncherLabel(item);
+ addListenerToLabel(label);
+ }
+
+ /**
+ * Creates the launcher label.
+ *
+ * @param item the item
+ * @return the launcher label
+ */
+ private LauncherLabel createLauncherLabel(final LauncherItem item) {
+ final LauncherLabel label = new LauncherLabel(this, SWT.CENTER);
+ label.setText(item.title);
+ label.setImage(SWTGraphicUtil.createImageFromFile(item.image));
+ label.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, false);
+ gd.widthHint = 192;
+ gd.heightHint = 220;
+ label.setLayoutData(gd);
+ item.label = label;
+ return label;
+ }
+
+ /**
+ * Adds the listener to label.
+ *
+ * @param label the label
+ */
+ private void addListenerToLabel(final LauncherLabel label) {
+ label.addListener(SWT.KeyUp, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ handleKeyPressedEvent(event);
+ }
+ });
+
+ label.addListener(SWT.MouseUp, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ handleClickEvent(event);
+ }
+ });
+
+ label.addListener(SWT.MouseDoubleClick, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ handleDoubleClickEvent(event);
+ }
+ });
+ }
+
+ /**
+ * Code executed when a key is pressed.
+ *
+ * @param event Event
+ */
+ private void handleKeyPressedEvent(final Event event) {
+ switch (event.keyCode) {
+ case SWT.ARROW_LEFT:
+ if (this.selection == -1) {
+ this.selection = 0;
+ changeColor(this.selection, true);
+ return;
+ }
+
+ if (this.selection % 2 != 0) {
+ changeColor(this.selection, false);
+ this.selection--;
+ changeColor(this.selection, true);
+ }
+ break;
+ case SWT.ARROW_UP:
+ if (this.selection == -1) {
+ this.selection = 0;
+ changeColor(this.selection, true);
+ return;
+ }
+ if (this.selection >= 2) {
+ changeColor(this.selection, false);
+ this.selection -= 2;
+ changeColor(this.selection, true);
+ }
+ break;
+ case SWT.ARROW_RIGHT:
+ if (this.selection == -1) {
+ this.selection = 0;
+ changeColor(this.selection, true);
+ return;
+ }
+ if (this.selection % 2 == 0) {
+ changeColor(this.selection, false);
+ this.selection++;
+ changeColor(this.selection, true);
+ }
+ break;
+ case SWT.ARROW_DOWN:
+ if (this.selection == -1) {
+ this.selection = 0;
+ changeColor(this.selection, true);
+ return;
+ }
+ if (this.selection <= this.items.size() - 2) {
+ changeColor(this.selection, false);
+ this.selection += 2;
+ changeColor(this.selection, true);
+ }
+ break;
+ case SWT.HOME:
+ changeColor(this.selection, false);
+ this.selection = 0;
+ changeColor(this.selection, true);
+ break;
+ case SWT.END:
+ changeColor(this.selection, false);
+ this.selection = this.items.size() - 1;
+ changeColor(this.selection, true);
+ break;
+ }
+
+ }
+
+ /**
+ * Code executed when one clicks on the button.
+ *
+ * @param event Event
+ */
+ private void handleClickEvent(final Event event) {
+ for (int i = 0; i < this.items.size(); i++) {
+ final LauncherItem item = this.items.get(i);
+ if (item.label != null && item.label.equals(event.widget)) {
+ if (this.selection != i) {
+ changeColor(this.selection, false);
+ this.selection = i;
+ changeColor(this.selection, true);
+ }
+ return;
+ }
+ }
+ }
+
+ /**
+ * Change the background color of a given button.
+ *
+ * @param index index of the button
+ * @param isSelected if <code>true</code>, the background is the light
+ * shadow. Otherwise, the background color is white
+ */
+ private void changeColor(final int index, final boolean isSelected) {
+ if (index != -1 && this.items.get(index).label != null) {
+ this.items.get(index).label.setBackground(isSelected ? getDisplay().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW) : getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ }
+ }
+
+ /**
+ * Code executed when one double-clicks on a button.
+ *
+ * @param event Event
+ */
+ private void handleDoubleClickEvent(final Event event) {
+ for (int i = 0; i < this.items.size(); i++) {
+ final LauncherItem item = this.items.get(i);
+ if (item.label != null && item.label.equals(event.widget)) {
+ if (this.selection != i) {
+ changeColor(this.selection, false);
+ this.selection = i;
+ changeColor(this.selection, true);
+ }
+ startAnimation(i, event);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Start the animation for a given button.
+ *
+ * @param index index of the selected button
+ * @param event event (propagated to the selection listeners)
+ */
+ private void startAnimation(final int index, final Event event) {
+ final LauncherLabel label = this.items.get(index).label;
+ getDisplay().timerExec(0, new Runnable() {
+ @Override
+ public void run() {
+ if (label.incrementAnimation()) {
+ getDisplay().timerExec(20, this);
+ } else {
+ fireSelectionListeners(event);
+ }
+ }
+ });
+
+ }
+
+ /**
+ * Fire the selection listeners.
+ *
+ * @param originalEvent mouse event
+ * @return <code>true</code> if the selection could be changed,
+ * <code>false</code> otherwise
+ */
+ private boolean fireSelectionListeners(final Event originalEvent) {
+ final Event event = new Event();
+
+ event.button = originalEvent.button;
+ event.display = this.getDisplay();
+ event.item = null;
+ event.widget = this;
+ event.data = null;
+ event.time = originalEvent.time;
+ event.x = originalEvent.x;
+ event.y = originalEvent.y;
+
+ for (final SelectionListener listener : this.selectionListeners) {
+ final SelectionEvent selEvent = new SelectionEvent(event);
+ listener.widgetSelected(selEvent);
+ if (!selEvent.doit) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Add an item to the launcher.
+ *
+ * @param title text associated to this item
+ * @param image image associated to this item
+ */
+ public void addItem(final String title, final String image) {
+ checkWidget();
+ this.items.add(new LauncherItem(title, image));
+ this.needRedraw = 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();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ this.selectionListeners.add(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) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ this.selectionListeners.remove(listener);
+ }
+
+ /**
+ * Return the selected button.
+ *
+ * @return the index of the selected 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 int getSelection() {
+ checkWidget();
+ return this.selection;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/LauncherItem.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/LauncherItem.java
new file mode 100644
index 0000000..e25b49d
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/LauncherItem.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.launcher;
+
+/**
+ * Instances of this class are POJO to store information handled by the Launcher
+ * widget I could have used a inner class but I prefer this solution :).
+ */
+class LauncherItem {
+
+ /** The title. */
+ String title;
+
+ /** The image. */
+ String image;
+
+ /** The label. */
+ LauncherLabel label;
+
+ /**
+ * Constructor.
+ *
+ * @param title text associated to the item
+ * @param image image associated to the item
+ */
+ LauncherItem(final String title, final String image) {
+ this.title = title;
+ this.image = image;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/LauncherLabel.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/LauncherLabel.java
new file mode 100644
index 0000000..3c22a79
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/launcher/LauncherLabel.java
@@ -0,0 +1,371 @@
+/*******************************************************************************
+ * 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.launcher;
+
+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.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.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instance of this class are a button with text, image and a nice animation
+ * effect.
+ */
+class LauncherLabel extends Canvas {
+
+ /** The text. */
+ private String text;
+
+ /** The image. */
+ private Image image;
+
+ /** The font. */
+ private Font font;
+
+ /** The Constant GAP. */
+ private static final int GAP = 12;
+
+ /** The draw flags. */
+ private static int DRAW_FLAGS = SWT.DRAW_MNEMONIC | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT | SWT.DRAW_DELIMITER;
+
+ /** The Constant DEFAULT_MARGIN. */
+ private static final int DEFAULT_MARGIN = 5;
+
+ /** The left margin. */
+ private int leftMargin = DEFAULT_MARGIN;
+
+ /** The top margin. */
+ private int topMargin = DEFAULT_MARGIN;
+
+ /** The right margin. */
+ private int rightMargin = DEFAULT_MARGIN;
+
+ /** The bottom margin. */
+ private int bottomMargin = DEFAULT_MARGIN;
+
+ /** The text size. */
+ private Point textSize;
+
+ /** The Constant MAX_NUMBER_OF_STEPS. */
+ private static final int MAX_NUMBER_OF_STEPS = 10;
+
+ /** The animation step. */
+ private int animationStep = 0;
+
+ /**
+ * 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>
+ *
+ */
+ LauncherLabel(final Composite parent, final int style) {
+ super(parent, style | SWT.BORDER | SWT.DOUBLE_BUFFERED);
+
+ final Font original = super.getFont();
+
+ final Font defaultFont = new Font(getDisplay(), original.getFontData()[0].getName(), 18, SWT.BOLD);
+ this.font = defaultFont;
+ SWTGraphicUtil.addDisposer(this, defaultFont);
+
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(final PaintEvent event) {
+ onPaint(event);
+ }
+ });
+
+ }
+
+ /**
+ * Draw the content of the LLabel.
+ *
+ * @param event paintevent
+ */
+ private void onPaint(final PaintEvent event) {
+ final Rectangle rect = getClientArea();
+ if (rect.width == 0 || rect.height == 0) {
+ return;
+ }
+
+ final Image bufferImage = new Image(getDisplay(), Math.max(1, rect.width), Math.max(1, rect.height));
+
+ final GC gc = new GC(bufferImage);
+ gc.setForeground(getForeground());
+ gc.setBackground(getBackground());
+
+ gc.fillRectangle(rect);
+
+ final Point extent = getTotalSize(this.image.getBounds().width, this.image.getBounds().height);
+ final int xImage = (rect.width - this.image.getBounds().width) / 2;
+ final int yImage = (rect.height - extent.y) / 2;
+ gc.drawImage(this.image, xImage, yImage);
+
+ gc.setFont(this.font);
+ final int xText = (rect.width - this.textSize.x) / 2;
+ final int yText = yImage + this.image.getBounds().height + GAP - this.textSize.y / 2;
+ gc.drawString(this.text, xText, yText);
+
+ if (this.animationStep != 0) {
+ final float zoom = 1f + this.animationStep * (Math.max(extent.x, extent.y) - Math.max(this.image.getBounds().width, this.image.getBounds().height)) / MAX_NUMBER_OF_STEPS / 100f;
+
+ final int newSizeX = (int) (this.image.getBounds().width * zoom);
+ final int newSizeY = (int) (this.image.getBounds().height * zoom);
+
+ gc.setAntialias(SWT.ON);
+ gc.setInterpolation(SWT.HIGH);
+
+ gc.setAlpha(255 - 255 / MAX_NUMBER_OF_STEPS * this.animationStep);
+
+ final Point extentZoomedImage = getTotalSize(newSizeX, newSizeY);
+ final int xZoomedImage = (rect.width - newSizeX) / 2;
+ final int yZoomedImage = (rect.height - extentZoomedImage.y) / 2;
+ gc.drawImage(this.image, 0, 0, this.image.getBounds().width, this.image.getBounds().height, xZoomedImage, yZoomedImage, (int) (this.image.getBounds().width * zoom), (int) (this.image.getBounds().height * zoom));
+
+ }
+
+ gc.dispose();
+
+ event.gc.drawImage(bufferImage, 0, 0);
+
+ bufferImage.dispose();
+
+ }
+
+ /**
+ * 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();
+ final Point e = getTotalSize(this.image.getBounds().width, this.image.getBounds().height);
+ if (wHint == SWT.DEFAULT) {
+ e.x += this.leftMargin + this.rightMargin;
+ } else {
+ e.x = wHint;
+ }
+ if (hHint == SWT.DEFAULT) {
+ e.y += this.topMargin + this.bottomMargin;
+ } else {
+ e.y = hHint;
+ }
+ return e;
+ }
+
+ /**
+ * Compute the size of the content (image + text + gap).
+ *
+ * @param imgWidth image width
+ * @param imgHeight image height
+ * @return the size of the content
+ */
+ private Point getTotalSize(final int imgWidth, final int imgHeight) {
+ final Point size = new Point(0, 0);
+
+ int textWidth = 0;
+ int textHeight = 0;
+
+ if (this.textSize == null) {
+ final GC gc = new GC(this);
+ gc.setFont(this.font);
+
+ this.textSize = gc.textExtent(this.text, DRAW_FLAGS);
+ gc.dispose();
+
+ }
+ textWidth = this.textSize.x;
+ textHeight = this.textSize.y;
+
+ size.x = Math.max(imgWidth, textWidth);
+ size.y = imgHeight + GAP + textHeight;
+
+ return size;
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @return the text
+ */
+ String getText() {
+ return this.text;
+ }
+
+ /**
+ * Sets the text.
+ *
+ * @param text the text to set
+ */
+ void setText(final String text) {
+ this.text = text;
+ }
+
+ /**
+ * Gets the image.
+ *
+ * @return the image
+ */
+ Image getImage() {
+ return this.image;
+ }
+
+ /**
+ * Sets the image.
+ *
+ * @param image the image to set
+ */
+ void setImage(final Image image) {
+ this.image = image;
+ }
+
+ /**
+ * Gets the font.
+ *
+ * @return the font
+ */
+ @Override
+ public Font getFont() {
+ return this.font;
+ }
+
+ /**
+ * Sets the font.
+ *
+ * @param font the font to set
+ */
+ @Override
+ public void setFont(final Font font) {
+ this.font = font;
+ }
+
+ /**
+ * Increment the steps of the animation.
+ *
+ * @return true if animation keeps running, false otherwise
+ */
+ boolean incrementAnimation() {
+ this.animationStep++;
+ final boolean stopAnimation = this.animationStep > MAX_NUMBER_OF_STEPS;
+
+ if (stopAnimation) {
+ this.animationStep = 0;
+ }
+ if (!isDisposed()) {
+ redraw();
+ }
+ return !stopAnimation;
+ }
+
+ /**
+ * Gets the left margin.
+ *
+ * @return the left margin
+ */
+ public int getLeftMargin() {
+ return this.leftMargin;
+ }
+
+ /**
+ * Sets the left margin.
+ *
+ * @param leftMargin the left margin to set
+ */
+ public void setLeftMargin(final int leftMargin) {
+ this.leftMargin = leftMargin;
+ }
+
+ /**
+ * Gets the top margin.
+ *
+ * @return the top margin
+ */
+ public int getTopMargin() {
+ return this.topMargin;
+ }
+
+ /**
+ * Sets the top margin.
+ *
+ * @param topMargin the top margin to set
+ */
+ public void setTopMargin(final int topMargin) {
+ this.topMargin = topMargin;
+ }
+
+ /**
+ * Gets the right margin.
+ *
+ * @return the right margin
+ */
+ public int getRightMargin() {
+ return this.rightMargin;
+ }
+
+ /**
+ * Sets the right margin.
+ *
+ * @param rightMargin the right margin to set
+ */
+ public void setRightMargin(final int rightMargin) {
+ this.rightMargin = rightMargin;
+ }
+
+ /**
+ * Gets the bottom margin.
+ *
+ * @return the bottom margin
+ */
+ public int getBottomMargin() {
+ return this.bottomMargin;
+ }
+
+ /**
+ * Sets the bottom margin.
+ *
+ * @param bottomMargin the bottom margin to set
+ */
+ public void setBottomMargin(final int bottomMargin) {
+ this.bottomMargin = bottomMargin;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/login/LoginDialog.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/login/LoginDialog.java
new file mode 100644
index 0000000..e5af262
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/login/LoginDialog.java
@@ -0,0 +1,576 @@
+/*******************************************************************************
+ * 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.login;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+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.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Path;
+import org.eclipse.swt.graphics.Pattern;
+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.Canvas;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.opalDialog.Dialog;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are Login Dialog box, which is composed of
+ * <p>
+ * <dl>
+ * <dt><b>A login</b></dt>
+ * <dt><b>A password</b></dt>
+ * <dt><b>An image</b></dt>
+ * <dd>(optional)</dd>
+ * <dt><b>A description</b></dt>
+ * <dd>(optional)</dd>
+ * <dt><b>A checkbox "remember the password"</b></dt>
+ * <dd>(optional)</dd>
+ * </dl>
+ * </p>
+ * .
+ */
+public class LoginDialog {
+
+ /** The image. */
+ private Image image;
+
+ /** The description. */
+ private String description;
+
+ /** The login. */
+ private String login;
+
+ /** The password. */
+ private String password;
+
+ /** The autorized login. */
+ private List<String> autorizedLogin;
+
+ /** The display remember password. */
+ private boolean displayRememberPassword;
+
+ /** The remember password. */
+ private boolean rememberPassword;
+
+ /** The verifier. */
+ private LoginDialogVerifier verifier;
+
+ /** The shell. */
+ private Shell shell;
+
+ /** The returned value. */
+ private boolean returnedValue;
+
+ /** The button ok. */
+ private Button buttonOk;
+
+ /**
+ * Constructor.
+ */
+ public LoginDialog() {
+ this.displayRememberPassword = true;
+ }
+
+ /**
+ * Open the Login box.
+ *
+ * @return <code>true</code> if the authentication is OK, <code>false</code>
+ * if the user pressed on cancel.
+ */
+ public boolean open() {
+ if (this.verifier == null) {
+ throw new IllegalArgumentException("Please set a verifier before opening the dialog box");
+ }
+
+ buildDialog();
+ openShell();
+
+ return this.returnedValue;
+ }
+
+ /**
+ * Build the dialog box.
+ */
+ private void buildDialog() {
+ buildShell();
+ buildImage();
+ buildDescription();
+ buildLogin();
+ buildPassword();
+ if (this.displayRememberPassword) {
+ buildRememberPassword();
+ }
+ buildButtons();
+ }
+
+ /**
+ * Build the shell.
+ */
+ private void buildShell() {
+ this.shell = new Shell(SWT.SYSTEM_MODAL | SWT.TITLE | SWT.BORDER);
+ this.shell.setText(ResourceManager.getLabel(ResourceManager.LOGIN));
+ this.shell.setLayout(new GridLayout(4, false));
+ }
+
+ /**
+ * Build the image on top of the login box. If no image has been set, create
+ * a default image
+ */
+ private void buildImage() {
+ final Canvas canvas = new Canvas(this.shell, SWT.DOUBLE_BUFFERED);
+ final GridData gridData = new GridData(GridData.FILL, GridData.FILL, true, false, 4, 1);
+ gridData.widthHint = 400;
+ gridData.heightHint = 60;
+ canvas.setLayoutData(gridData);
+ canvas.addPaintListener(new PaintListener() {
+
+ @Override
+ public void paintControl(final PaintEvent e) {
+ e.gc.drawImage(LoginDialog.this.image == null ? createDefaultImage(e.width, e.height) : LoginDialog.this.image, 0, 0);
+ }
+ });
+
+ }
+
+ /**
+ * Create a default image. It is a port of the image used by the Login Box
+ * in the project SwingX
+ *
+ * @param w width
+ * @param h height
+ * @return a default image (blue wave)
+ */
+ private Image createDefaultImage(final int w, final int h) {
+ final Display display = Display.getCurrent();
+ final Color backgroundColor = new Color(display, 49, 121, 242);
+ final Color gradientColor1 = new Color(display, 155, 185, 245);
+ final Color gradientColor2 = new Color(display, 53, 123, 242);
+
+ final Image img = new Image(display, w, h);
+ final GC gc = new GC(img);
+ gc.setAdvanced(true);
+ gc.setAntialias(SWT.ON);
+ gc.setBackground(backgroundColor);
+ gc.fillRectangle(0, 0, w, h);
+
+ final Path curveShape = new Path(display);
+ curveShape.moveTo(0, h * .6f);
+ curveShape.cubicTo(w * .167f, h * 1.2f, w * .667f, h * -.5f, w, h * .75f);
+ curveShape.lineTo(w, h);
+ curveShape.lineTo(0, h);
+ curveShape.lineTo(0, h * .8f);
+ curveShape.close();
+
+ final Pattern pattern = new Pattern(display, 0, 0, 1, h * 1.2f, gradientColor1, gradientColor2);
+ gc.setBackgroundPattern(pattern);
+ gc.fillPath(curveShape);
+
+ final Font font = new Font(display, "Arial Bold", 30, SWT.NONE);
+ gc.setFont(font);
+ gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
+ final Point textSize = gc.stringExtent(ResourceManager.getLabel(ResourceManager.LOGIN));
+ gc.drawString(ResourceManager.getLabel(ResourceManager.LOGIN), (int) (w * .05f), (h - textSize.y) / 2, true);
+
+ font.dispose();
+ curveShape.dispose();
+ pattern.dispose();
+ backgroundColor.dispose();
+ gradientColor1.dispose();
+ gradientColor2.dispose();
+ gc.dispose();
+ return img;
+ }
+
+ /**
+ * Build the description part of the box.
+ */
+ private void buildDescription() {
+ final Label label = new Label(this.shell, SWT.NONE);
+ final GridData gridData = new GridData(GridData.FILL, GridData.BEGINNING, true, false, 4, 1);
+ gridData.verticalIndent = 5;
+ gridData.horizontalIndent = 5;
+ label.setLayoutData(gridData);
+ final Font bold = SWTGraphicUtil.buildFontFrom(label, SWT.BOLD);
+ label.setFont(bold);
+ SWTGraphicUtil.addDisposer(label, bold);
+
+ if (this.description == null || this.description.trim().equals("")) {
+ label.setText(" ");
+ } else {
+ label.setText(this.description);
+ }
+ }
+
+ /**
+ * Build the login part of the box.
+ */
+ private void buildLogin() {
+ final Label label = new Label(this.shell, SWT.NONE);
+ final GridData gridData = new GridData(GridData.END, GridData.END, false, false, 1, 1);
+ gridData.horizontalIndent = 35;
+ gridData.verticalIndent = 15;
+ label.setLayoutData(gridData);
+ label.setText(ResourceManager.getLabel(ResourceManager.NAME));
+
+ if (this.autorizedLogin != null && !this.autorizedLogin.isEmpty()) {
+ // Combo
+ buildLoginCombo();
+ } else {
+ // Text
+ buildLoginText();
+ }
+
+ }
+
+ /**
+ * Builds the login combo.
+ */
+ private void buildLoginCombo() {
+ final Combo combo = new Combo(this.shell, SWT.BORDER | SWT.READ_ONLY);
+
+ combo.setLayoutData(new GridData(GridData.FILL, GridData.END, true, false, 3, 1));
+ for (final String loginToAdd : this.autorizedLogin) {
+ combo.add(loginToAdd);
+ }
+ combo.setText(this.login == null ? "" : this.login);
+ combo.setFocus();
+ combo.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(final ModifyEvent e) {
+ LoginDialog.this.login = combo.getText();
+ changeButtonOkState();
+ }
+ });
+ }
+
+ /**
+ * Builds the login text.
+ */
+ private void buildLoginText() {
+ final Text text = new Text(this.shell, SWT.BORDER);
+ text.setText(this.login == null ? "" : this.login);
+ text.setLayoutData(new GridData(GridData.FILL, GridData.END, true, false, 3, 1));
+ text.setFocus();
+ text.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(final ModifyEvent e) {
+ LoginDialog.this.login = text.getText();
+ changeButtonOkState();
+ }
+ });
+ }
+
+ /**
+ * Build the password part of the box.
+ */
+ private void buildPassword() {
+ final Label label = new Label(this.shell, SWT.NONE);
+ final GridData gridData = new GridData(GridData.END, GridData.CENTER, false, false, 1, 1);
+ gridData.horizontalIndent = 35;
+ label.setLayoutData(gridData);
+ label.setText(ResourceManager.getLabel(ResourceManager.PASSWORD));
+
+ final Text text = new Text(this.shell, SWT.PASSWORD | SWT.BORDER);
+ text.setText(this.password == null ? "" : this.password);
+ text.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1));
+ text.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(final ModifyEvent e) {
+ LoginDialog.this.password = text.getText();
+ changeButtonOkState();
+ }
+ });
+ }
+
+ /**
+ * Enable/Disable the button when the login and the password is empty (or
+ * not).
+ */
+ private void changeButtonOkState() {
+ final boolean loginEntered = this.login != null && !this.login.trim().equals("");
+ final boolean passwordEntered = this.password != null && !this.password.trim().equals("");
+ this.buttonOk.setEnabled(loginEntered && passwordEntered);
+ }
+
+ /**
+ * Build the "remember password" part of the box.
+ */
+ private void buildRememberPassword() {
+ final Button checkbox = new Button(this.shell, SWT.CHECK);
+ final GridData gridData = new GridData(GridData.BEGINNING, GridData.CENTER, true, false, 4, 1);
+ gridData.horizontalIndent = 35;
+ checkbox.setLayoutData(gridData);
+ checkbox.setText(ResourceManager.getLabel(ResourceManager.REMEMBER_PASSWORD));
+ checkbox.setSelection(this.rememberPassword);
+ }
+
+ /**
+ * Build the buttons.
+ */
+ private void buildButtons() {
+ buildOkButton();
+ buildCancelButton();
+ }
+
+ /**
+ * Builds the ok button.
+ */
+ private void buildOkButton() {
+ this.buttonOk = new Button(this.shell, SWT.PUSH);
+ final GridData gdOk = new GridData(GridData.END, GridData.CENTER, true, false, 3, 1);
+ gdOk.verticalIndent = 60;
+ gdOk.minimumWidth = 80;
+ this.buttonOk.setLayoutData(gdOk);
+ this.buttonOk.setText(ResourceManager.getLabel(ResourceManager.OK));
+ this.buttonOk.setEnabled(false);
+
+ this.buttonOk.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent selectionEvent) {
+ try {
+ LoginDialog.this.verifier.authenticate(LoginDialog.this.login, LoginDialog.this.password);
+ LoginDialog.this.returnedValue = true;
+ LoginDialog.this.shell.dispose();
+ } catch (final Exception e) { // NOSONAR
+ Dialog.error(ResourceManager.getLabel(ResourceManager.LOGIN_FAILED), e.getMessage());
+ for (final Control control : LoginDialog.this.shell.getChildren()) {
+ if (control instanceof Text || control instanceof Combo) {
+ control.setFocus();
+ break;
+ }
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Builds the cancel button.
+ */
+ private void buildCancelButton() {
+ final Button buttonCancel = new Button(this.shell, SWT.PUSH);
+ final GridData gdCancel = new GridData(GridData.FILL, GridData.CENTER, false, false);
+ gdCancel.widthHint = 80;
+ gdCancel.verticalIndent = 60;
+ buttonCancel.setLayoutData(gdCancel);
+ buttonCancel.setText(ResourceManager.getLabel(ResourceManager.CANCEL));
+ buttonCancel.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ LoginDialog.this.returnedValue = false;
+ LoginDialog.this.shell.dispose();
+ }
+ });
+ }
+
+ /**
+ * Open the shell.
+ */
+ private void openShell() {
+ this.shell.setDefaultButton(this.buttonOk);
+ this.shell.pack();
+ this.shell.open();
+ SWTGraphicUtil.centerShell(this.shell);
+ while (!this.shell.isDisposed()) {
+ if (!this.shell.getDisplay().readAndDispatch()) {
+ this.shell.getDisplay().sleep();
+ }
+ }
+ }
+
+ // ------------- Getters & Setters
+ /**
+ * Gets the image.
+ *
+ * @return the image
+ */
+ public Image getImage() {
+ return this.image;
+ }
+
+ /**
+ * Gets the description.
+ *
+ * @return the description
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Gets the login.
+ *
+ * @return the login
+ */
+ public String getLogin() {
+ return this.login == null ? null : this.login.trim();
+ }
+
+ /**
+ * Gets the password.
+ *
+ * @return the password
+ */
+ public String getPassword() {
+ return this.password == null ? null : this.password.trim();
+ }
+
+ /**
+ * Gets the autorized login.
+ *
+ * @return the list of autorized logins
+ */
+ public List<String> getAutorizedLogin() {
+ return this.autorizedLogin;
+ }
+
+ /**
+ * Checks if is display remember password.
+ *
+ * @return <code>true</code> if the checkbox "remember the password" is
+ * displayed, <code>false</code> otherwise
+ */
+ public boolean isDisplayRememberPassword() {
+ return this.displayRememberPassword;
+ }
+
+ /**
+ * Checks if is remember password.
+ *
+ * @return <code>true</code> if the checkbox "remember the password" is
+ * checked, <code>false</code> otherwise
+ */
+ public boolean isRememberPassword() {
+ return this.rememberPassword;
+ }
+
+ /**
+ * Gets the verifier.
+ *
+ * @return the verifier associated to this box
+ */
+ public LoginDialogVerifier getVerifier() {
+ return this.verifier;
+ }
+
+ /**
+ * Sets the image.
+ *
+ * @param image the image to set
+ */
+ public void setImage(final Image image) {
+ this.image = image;
+ }
+
+ /**
+ * Sets the description.
+ *
+ * @param description the description to set
+ */
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ /**
+ * Sets the login.
+ *
+ * @param login the login to set
+ */
+ public void setLogin(final String login) {
+ this.login = login;
+ }
+
+ /**
+ * Sets the password.
+ *
+ * @param password the password to set
+ */
+ public void setPassword(final String password) {
+ this.password = password;
+ }
+
+ /**
+ * Sets the autorized login.
+ *
+ * @param autorizedLogin the list of autorized logins to set
+ */
+ public void setAutorizedLogin(final List<String> autorizedLogin) {
+ this.autorizedLogin = autorizedLogin;
+ }
+
+ /**
+ * Sets the autorized login.
+ *
+ * @param autorizedLogin the list of autorized logins to set
+ */
+ public void setAutorizedLogin(final String... autorizedLogin) {
+ this.autorizedLogin = Arrays.asList(autorizedLogin);
+ }
+
+ /**
+ * Sets the display remember password.
+ *
+ * @param displayRememberPassword if <code>true</code>, the checkbox
+ * "remember the password" is displayed
+ */
+ public void setDisplayRememberPassword(final boolean displayRememberPassword) {
+ this.displayRememberPassword = displayRememberPassword;
+ }
+
+ /**
+ * Sets the remember password.
+ *
+ * @param rememberPassword if <code>true</code>, the checkbox
+ * "remember the password" is selected
+ */
+ public void setRememberPassword(final boolean rememberPassword) {
+ this.rememberPassword = rememberPassword;
+ }
+
+ /**
+ * Sets the verifier.
+ *
+ * @param verifier the verifier to set
+ */
+ public void setVerifier(final LoginDialogVerifier verifier) {
+ this.verifier = verifier;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/login/LoginDialogVerifier.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/login/LoginDialogVerifier.java
new file mode 100644
index 0000000..5319409
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/login/LoginDialogVerifier.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.login;
+
+/**
+ * This interface describes a verifier for the LoginDialogWidget.
+ */
+public interface LoginDialogVerifier {
+
+ /**
+ * Check if the couple login/password is correct.
+ *
+ * @param login login entered by the user
+ * @param password password entered by the user
+ * @throws Exception if the couple login/password is wrong. The description
+ * of the exception contains the error message that is gonna be
+ * displayed. For instance, an implementation can throw the
+ * exception *
+ * <code>new Exception("Unable to connect to the LDAP Server")</code>
+ */
+ void authenticate(String login, String password) throws Exception;
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoice.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoice.java
new file mode 100644
index 0000000..a20d6b9
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoice.java
@@ -0,0 +1,1336 @@
+/*******************************************************************************
+ * 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.multiChoice;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+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.Listener;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.SimpleSelectionAdapter;
+
+/**
+ * The MultiChoice class represents a selectable user interface object that combines a read-only text-field and a set of checkboxes.
+ *
+ * <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>NONE</dd>
+ * <dt><b>Events:</b>
+ * <dd>Selection</dd>
+ * </dl>
+ *
+ * @param <T> Class of objects represented by this widget
+ */
+public class MultiChoice<T> extends Composite {
+
+ /** The text. */
+ private Text text;
+
+ /** The arrow. */
+ private Button arrow;
+
+ /** The popup. */
+ private Shell popup;
+
+ /** The scrolled composite. */
+ private ScrolledComposite scrolledComposite;
+
+ /** The filter. */
+ private Listener listener, filter;
+
+ /** The number of columns. */
+ private int numberOfColumns = 2;
+
+ /** The elements. */
+ private List<T> elements;
+
+ /** The selection. */
+ private Set<T> selection;
+
+ /** The checkboxes. */
+ private List<Button> checkboxes;
+
+ /** The has focus. */
+ private boolean hasFocus;
+
+ /** The selection listener. */
+ private MultiChoiceSelectionListener<T> selectionListener;
+
+ /** The last modified. */
+ private T lastModified;
+
+ /** The background. */
+ private Color foreground, background;
+
+ /** The font. */
+ private Font font;
+
+ /** The separator. */
+ private String separator;
+
+ /** The label provider. */
+ private MultiChoiceLabelProvider labelProvider;
+
+ /** The preferred height of popup. */
+ private int preferredHeightOfPopup;
+
+ /**
+ * 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 MultiChoice(final Composite parent, final int style) {
+ this(parent, style, null);
+ }
+
+ /**
+ * 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
+ * @param elements list of elements displayed by this widget
+ *
+ * @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 MultiChoice(final Composite parent, final int style, final List<T> elements) {
+ super(parent, style);
+
+ final GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = gridLayout.marginWidth = gridLayout.marginHeight = 0;
+ this.setLayout(gridLayout);
+
+ int readOnlyStyle;
+ if ((style & SWT.READ_ONLY) == SWT.READ_ONLY) {
+ readOnlyStyle = SWT.READ_ONLY;
+ } else {
+ readOnlyStyle = SWT.NONE;
+ }
+
+ this.text = new Text(this, SWT.SINGLE | readOnlyStyle | SWT.BORDER);
+ this.text.setBackground(this.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+ this.text.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+
+ this.arrow = new Button(this, SWT.ARROW | SWT.RIGHT);
+ this.arrow.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+
+ createGlobalListener();
+ addListeners();
+
+ this.filter = new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ final Shell shell = ((Control) event.widget).getShell();
+ if (shell == MultiChoice.this.getShell()) {
+ handleFocusEvents(SWT.FocusOut);
+ }
+ }
+ };
+
+ this.selection = new LinkedHashSet<T>();
+ this.elements = elements;
+ this.separator = ",";
+ this.labelProvider = new MultiChoiceDefaultLabelProvider();
+
+ createPopup();
+ setLabel();
+ }
+
+ /**
+ * Creates the global listener.
+ */
+ private void createGlobalListener() {
+ this.listener = new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ if (MultiChoice.this.popup == event.widget) {
+ handlePopupEvent(event);
+ return;
+ }
+
+ if (MultiChoice.this.arrow == event.widget) {
+ handleButtonEvent(event);
+ return;
+ }
+
+ if (MultiChoice.this == event.widget) {
+ handleMultiChoiceEvents(event);
+ return;
+ }
+
+ if (getShell() == event.widget) {
+ getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (isDisposed()) {
+ return;
+ }
+ handleFocusEvents(SWT.FocusOut);
+ }
+ });
+ }
+ }
+ };
+ }
+
+ /**
+ * Adds the listeners.
+ */
+ private void addListeners() {
+
+ final int[] multiChoiceEvent = { SWT.Dispose, SWT.Move, SWT.Resize };
+ for (final int element : multiChoiceEvent) {
+ this.addListener(element, this.listener);
+ }
+
+ if ((getStyle() & SWT.READ_ONLY) == 0) {
+ final Listener validationListener = new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ if (!MultiChoice.this.popup.isDisposed() && !MultiChoice.this.popup.isVisible()) {
+ validateEntry();
+ }
+ }
+ };
+ this.text.addListener(SWT.FocusOut, validationListener);
+ }
+
+ final int[] buttonEvents = { SWT.Selection, SWT.FocusIn };
+ for (final int buttonEvent : buttonEvents) {
+ this.arrow.addListener(buttonEvent, this.listener);
+ }
+ }
+
+ /**
+ * Validate entry.
+ */
+ protected void validateEntry() {
+ final String toValidate = this.text.getText();
+ final String[] elementsToValidate = toValidate.split(this.separator);
+ final List<String> fieldsInError = new ArrayList<String>();
+ this.selection.clear();
+ for (final String elementToValidate : elementsToValidate) {
+ final String temp = elementToValidate.trim();
+ if ("".equals(temp)) {
+ continue;
+ }
+
+ final T entry = convertEntry(temp);
+
+ if (entry == null) {
+ fieldsInError.add(temp);
+ } else {
+ this.selection.add(entry);
+ }
+ }
+
+ if (fieldsInError.size() == 0) {
+ updateSelection();
+ return;
+ }
+
+ final String messageToDisplay;
+ if (fieldsInError.size() == 1) {
+ messageToDisplay = String.format(ResourceManager.getLabel(ResourceManager.MULTICHOICE_MESSAGE), fieldsInError.get(0));
+ } else {
+ final StringBuilder sb = new StringBuilder();
+ final Iterator<String> it = fieldsInError.iterator();
+ while (it.hasNext()) {
+ sb.append(it.next());
+ if (it.hasNext()) {
+ sb.append(",");
+ }
+ }
+ messageToDisplay = String.format(ResourceManager.getLabel(ResourceManager.MULTICHOICE_MESSAGE_PLURAL), sb.toString());
+ }
+ getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ final MessageBox mb = new MessageBox(getShell(), SWT.OK | SWT.ICON_ERROR);
+ mb.setMessage(messageToDisplay);
+ mb.open();
+ MultiChoice.this.text.forceFocus();
+ }
+ });
+
+ }
+
+ /**
+ * Convert entry.
+ *
+ * @param elementToValidate the element to validate
+ * @return the t
+ */
+ private T convertEntry(final String elementToValidate) {
+ for (final T elt : this.elements) {
+ if (this.labelProvider.getText(elt).trim().equals(elementToValidate)) {
+ return elt;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds the argument to the end of the receiver's list.
+ *
+ * @param value the value
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string 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 add(final T value) {
+ checkWidget();
+ if (value == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (this.elements == null) {
+ this.elements = new ArrayList<T>();
+ }
+ this.elements.add(value);
+ refresh();
+ }
+
+ /**
+ * Adds the argument to the receiver's list at the given zero-relative
+ * index.
+ *
+ * @param value the value
+ * @param index the index for the item
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * <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 void add(final T value, final int index) {
+ checkWidget();
+ checkNullElement();
+ if (value == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ checkRange(index);
+
+ this.elements.add(index, value);
+ refresh();
+ }
+
+ /**
+ * Adds the argument to the end of the receiver's list.
+ *
+ * @param values new items
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string 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 addAll(final List<T> values) {
+ checkWidget();
+ if (values == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (this.elements == null) {
+ this.elements = new ArrayList<T>();
+ }
+ this.elements.addAll(values);
+ refresh();
+ }
+
+ /**
+ * Adds the argument to the end of the receiver's list.
+ *
+ * @param values new items
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the string 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 addAll(final T[] values) {
+ checkWidget();
+ if (values == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (this.elements == null) {
+ this.elements = new ArrayList<T>();
+ }
+ for (final T value : values) {
+ this.elements.add(value);
+ }
+ refresh();
+ }
+
+ /**
+ * Returns the item at the given, zero-relative index in the receiver's list. 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 NullPointerException if there is no item in the receiver
+ * @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 T getItem(final int index) {
+ checkWidget();
+ checkNullElement();
+ checkRange(index);
+
+ return this.elements.get(index);
+ }
+
+ /**
+ * Returns the number of items contained in the receiver's list.
+ *
+ * @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();
+ if (this.elements == null) {
+ return 0;
+ }
+
+ return this.elements.size();
+
+ }
+
+ /**
+ * Returns the list of items in the receiver's list.
+ * <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's list
+ *
+ * @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 List<T> getItems() {
+ checkWidget();
+ if (this.elements == null) {
+ return null;
+ }
+ return new ArrayList<T>(this.elements);
+ }
+
+ /**
+ * Removes the item from the receiver's list at the given zero-relative index.
+ *
+ * @param index the index for the item
+ * @exception NullPointerException if there is no item in the receiver
+ * @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 void removeAt(final int index) {
+ checkWidget();
+ checkNullElement();
+ checkRange(index);
+ final Object removedElement = this.elements.remove(index);
+ this.selection.remove(removedElement);
+ refresh();
+ }
+
+ /**
+ * Searches the receiver's list starting at the first item until an item is found that is equal to the argument, and removes that item from the list.
+ *
+ * @param object the item to remove
+ * @exception NullPointerException if there is no item in the receiver
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the object 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 remove(final T object) {
+ if (object == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ checkWidget();
+ checkNullElement();
+ this.elements.remove(object);
+ this.selection.remove(object);
+ refresh();
+ }
+
+ /**
+ * Remove all items of 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 void removeAll() {
+ checkWidget();
+ checkNullElement();
+ if (this.elements != null) {
+ this.elements.clear();
+ }
+ this.selection.clear();
+ refresh();
+ }
+
+ /**
+ * Sets the label provider.
+ *
+ * @param labelProvider the Label Provider to set
+ */
+ public void setLabelProvider(final MultiChoiceLabelProvider labelProvider) {
+ this.labelProvider = labelProvider;
+ }
+
+ /**
+ * Sets the selection of the receiver. If the item was already selected, it remains selected.
+ *
+ * @param selection the new selection
+ * @exception NullPointerException if there is no item in the receiver
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the selection 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 setSelection(final Set<T> selection) {
+ checkWidget();
+ checkNullElement();
+ if (selection == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ this.selection = selection;
+ updateSelection();
+ }
+
+ /**
+ * Selects all selected items in the receiver's list.
+ *
+ * @exception NullPointerException if there is no item 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 void selectAll() {
+ checkWidget();
+ checkNullElement();
+ this.selection.addAll(this.elements);
+ updateSelection();
+ }
+
+ /**
+ * Selects the item at the given zero-relative index in the receiver's list. If the item at the index was already selected, it remains selected.
+ *
+ * @param index the index of the item to select
+ * @exception NullPointerException if there is no item in the receiver
+ * @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 void selectAt(final int index) {
+ checkWidget();
+ checkNullElement();
+ checkRange(index);
+ this.selection.add(this.elements.get(index));
+ updateSelection();
+ }
+
+ /**
+ * Selects an item the receiver's list. If the item was already selected, it
+ * remains selected.
+ *
+ * @param value the value
+ * @exception NullPointerException if there is no item in the receiver
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the selection 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 select(final T value) {
+ checkWidget();
+ checkNullElement();
+ if (!this.elements.contains(value)) {
+ throw new IllegalArgumentException("Value not present in the widget");
+ }
+ this.selection.add(value);
+ updateSelection();
+ }
+
+ /**
+ * Selects items in the receiver. If the items were already selected, they remain selected.
+ *
+ * @param index the indexes of the items to select
+ * @exception NullPointerException if there is no item in the receiver
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the selection is null</li>
+ * <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 void setSelectedIndex(final int[] index) {
+ checkWidget();
+ checkNullElement();
+ for (final int i : index) {
+ checkRange(i);
+ this.selection.add(this.elements.get(i));
+ }
+ updateSelection();
+ }
+
+ /**
+ * Returns the zero-relative indices of the items which are currently selected in the receiver. The order of the indices is unspecified. The array is empty if no items are selected.
+ * <p>
+ * Note: This is not the actual structure used by the receiver to maintain its selection, so modifying the array will not affect the receiver.
+ * </p>
+ *
+ * @return the array of indices of the selected items
+ * @exception NullPointerException if there is no item 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 int[] getSelectedIndex() {
+ checkWidget();
+ checkNullElement();
+ final List<Integer> selectedIndex = new ArrayList<Integer>();
+ for (int i = 0; i < this.elements.size(); i++) {
+ if (this.selection.contains(this.elements.get(i))) {
+ selectedIndex.add(i);
+ }
+ }
+
+ final int[] returned = new int[selectedIndex.size()];
+ for (int i = 0; i < selectedIndex.size(); i++) {
+ returned[i] = selectedIndex.get(i);
+ }
+
+ return returned;
+ }
+
+ /**
+ * Returns an array of <code>Object</code>s that are currently selected in the receiver. The order of the items is unspecified. An empty array indicates that no items are selected.
+ * <p>
+ * Note: This is not the actual structure used by the receiver to maintain its selection, so modifying the array will not affect the receiver.
+ * </p>
+ *
+ * @return an array representing the selection
+ * @exception NullPointerException if there is no item 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 List<T> getSelection() {
+ checkWidget();
+ checkNullElement();
+ return new ArrayList<T>(this.selection);
+ }
+
+ /**
+ * Deselects the item at the given zero-relative index in the receiver's list. If the item at the index was already deselected, it remains deselected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to deselect
+ * @exception NullPointerException if there is no item in the receiver
+ * @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 void deselectAt(final int index) {
+ this.selection.remove(getItem(index));
+ updateSelection();
+ }
+
+ /**
+ * Deselects the item in the receiver's list. If the item at the index was already deselected, it remains deselected.
+ *
+ * @param value the item to deselect
+ * @exception NullPointerException if there is no item in the receiver
+ * @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 void deselect(final T value) {
+ checkWidget();
+ checkNullElement();
+ this.selection.remove(value);
+ updateSelection();
+ }
+
+ /**
+ * Deselects all items in the receiver's list.
+ *
+ * @exception NullPointerException if there is no item 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 void deselectAll() {
+ checkWidget();
+ checkNullElement();
+ this.selection.clear();
+ updateSelection();
+ }
+
+ /**
+ * Gets the number of columns.
+ *
+ * @return the number of columns
+ */
+ public int getNumberOfColumns() {
+ checkWidget();
+ return this.numberOfColumns;
+ }
+
+ /**
+ * Sets the number of columns.
+ *
+ * @param numberOfColumns the number of columns
+ */
+ public void setNumberOfColumns(final int numberOfColumns) {
+ checkWidget();
+ this.numberOfColumns = numberOfColumns;
+ this.popup.dispose();
+ this.popup = null;
+ createPopup();
+ }
+
+ /**
+ * Gets the separator.
+ *
+ * @return the separator used in the text field. Default value is ","
+ */
+ public String getSeparator() {
+ return this.separator;
+ }
+
+ /**
+ * Sets the separator.
+ *
+ * @param separator the new value of the separator
+ */
+ public void setSeparator(final String separator) {
+ this.separator = separator;
+ }
+
+ /**
+ * Gets the foreground.
+ *
+ * @return the foreground
+ * @see org.eclipse.swt.widgets.Control#getForeground()
+ */
+ @Override
+ public Color getForeground() {
+ return this.foreground;
+ }
+
+ /**
+ * Sets the foreground.
+ *
+ * @param foreground the new foreground
+ * @see org.eclipse.swt.widgets.Control#setForeground(org.eclipse.swt.graphics.Color)
+ */
+ @Override
+ public void setForeground(final Color foreground) {
+ this.foreground = foreground;
+ }
+
+ /**
+ * Gets the background.
+ *
+ * @return the background
+ * @see org.eclipse.swt.widgets.Control#getBackground()
+ */
+ @Override
+ public Color getBackground() {
+ return this.background;
+ }
+
+ /**
+ * Sets the background.
+ *
+ * @param background the new background
+ * @see org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics.Color)
+ */
+ @Override
+ public void setBackground(final Color background) {
+ this.background = background;
+ }
+
+ /**
+ * Gets the font.
+ *
+ * @return the font
+ * @see org.eclipse.swt.widgets.Control#getFont()
+ */
+ @Override
+ public Font getFont() {
+ return this.font;
+ }
+
+ /**
+ * Sets the font.
+ *
+ * @param font the new font
+ * @see org.eclipse.swt.widgets.Control#setFont(org.eclipse.swt.graphics.Font)
+ */
+ @Override
+ public void setFont(final Font font) {
+ this.font = font;
+ }
+
+ /**
+ * Refresh the widget (after the add of a new element for example).
+ */
+ public void refresh() {
+ checkWidget();
+ this.popup.dispose();
+ this.popup = null;
+ createPopup();
+ updateSelection();
+ }
+
+ /**
+ * 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.text);
+ final int spacer = gc.stringExtent(" ").x;
+ final int textWidth = gc.stringExtent(this.text.getText()).x;
+ gc.dispose();
+ final Point textSize = this.text.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);
+ }
+
+ /**
+ * 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.text.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.text.setToolTipText(txt);
+ }
+
+ /**
+ * Gets the selection listener.
+ *
+ * @return the selection listener
+ */
+ public SelectionListener getSelectionListener() {
+ checkWidget();
+ return this.selectionListener;
+ }
+
+ /**
+ * Sets the selection listener.
+ *
+ * @param selectionListener the new selection listener
+ */
+ public void setSelectionListener(final MultiChoiceSelectionListener<T> selectionListener) {
+ checkWidget();
+ this.selectionListener = selectionListener;
+ refresh();
+ }
+
+ /**
+ * Update the selection.
+ */
+ public void updateSelection() {
+ checkWidget();
+ if (isDisposed()) {
+ return;
+ }
+
+ if (this.popup == null || this.popup.isDisposed() || this.checkboxes == null) {
+ return;
+ }
+
+ for (int i = 0; i < this.checkboxes.size(); i++) {
+ final Button currentButton = this.checkboxes.get(i);
+ if (!currentButton.isDisposed()) {
+ final Object content = currentButton.getData();
+ currentButton.setSelection(this.selection.contains(content));
+ }
+ }
+ setLabel();
+
+ }
+
+ /**
+ * Gets the last modified.
+ *
+ * @return the last modified item
+ */
+ T getLastModified() {
+ return this.lastModified;
+ }
+
+ /**
+ * Gets the popup.
+ *
+ * @return the popup
+ */
+ Shell getPopup() {
+ return this.popup;
+ }
+
+ /**
+ * Create the popup that contains all checkboxes.
+ */
+ private void createPopup() {
+ this.popup = new Shell(getShell(), SWT.NO_TRIM | SWT.ON_TOP);
+ this.popup.setLayout(new FillLayout());
+
+ final int[] popupEvents = { SWT.Close, SWT.Deactivate, SWT.Dispose };
+ for (final int popupEvent : popupEvents) {
+ this.popup.addListener(popupEvent, this.listener);
+ }
+
+ if (this.elements == null) {
+ return;
+ }
+
+ this.scrolledComposite = new ScrolledComposite(this.popup, SWT.BORDER | SWT.V_SCROLL);
+ final Composite content = new Composite(this.scrolledComposite, SWT.NONE);
+ content.setLayout(new GridLayout(this.numberOfColumns, true));
+
+ this.checkboxes = new ArrayList<Button>(this.elements.size());
+ for (final T o : this.elements) {
+ final Button checkBoxButton = new Button(content, SWT.CHECK);
+
+ if (this.font != null) {
+ checkBoxButton.setFont(this.font);
+ }
+ if (this.foreground != null) {
+ checkBoxButton.setForeground(this.foreground);
+ }
+ if (this.background != null) {
+ checkBoxButton.setBackground(this.background);
+ }
+
+ checkBoxButton.setData(o);
+ checkBoxButton.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ checkBoxButton.setText(this.labelProvider.getText(o));
+ checkBoxButton.addSelectionListener(new SimpleSelectionAdapter() {
+ @Override
+ public void handle(final SelectionEvent e) {
+ if (checkBoxButton.getSelection()) {
+ MultiChoice.this.selection.add(o);
+ } else {
+ MultiChoice.this.selection.remove(o);
+ }
+ MultiChoice.this.lastModified = o;
+ setLabel();
+ }
+ });
+
+ if (this.selectionListener != null) {
+ checkBoxButton.addSelectionListener(this.selectionListener);
+ }
+
+ checkBoxButton.setSelection(this.selection.contains(o));
+ this.checkboxes.add(checkBoxButton);
+ }
+
+ this.scrolledComposite.setContent(content);
+ this.scrolledComposite.setExpandHorizontal(false);
+ this.scrolledComposite.setExpandVertical(true);
+ content.pack();
+ this.preferredHeightOfPopup = content.getSize().y;
+ }
+
+ /**
+ * Set the value of the label, based on the selected items.
+ */
+ private void setLabel() {
+ if (this.checkboxes == null) {
+ this.text.setText("");
+ return;
+ }
+
+ final List<String> values = new ArrayList<String>();
+ for (final Button current : this.checkboxes) {
+ if (current.getSelection()) {
+ values.add(current.getText());
+ }
+ }
+
+ final StringBuilder sb = new StringBuilder();
+ final Iterator<String> it = values.iterator();
+ while (it.hasNext()) {
+ sb.append(it.next());
+ if (it.hasNext()) {
+ sb.append(this.separator);
+ }
+ }
+
+ this.text.setText(sb.toString());
+ }
+
+ /**
+ * Handle a focus event.
+ *
+ * @param type type of the event to handle
+ */
+ private void handleFocusEvents(final int type) {
+ if (isDisposed()) {
+ return;
+ }
+ switch (type) {
+ 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;
+ }
+ }
+ }
+
+ /**
+ * Handle a multichoice event.
+ *
+ * @param event event to handle
+ */
+ private void handleMultiChoiceEvents(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:
+ changeVisibilityOfPopupWindow(false);
+ break;
+ case SWT.Resize:
+ if (isDropped()) {
+ changeVisibilityOfPopupWindow(false);
+ }
+ break;
+ }
+
+ }
+
+ /**
+ * Handle a button event.
+ *
+ * @param event event to hangle
+ */
+ private void handleButtonEvent(final Event event) {
+ switch (event.type) {
+ case SWT.FocusIn: {
+ handleFocusEvents(SWT.FocusIn);
+ break;
+ }
+ case SWT.Selection: {
+ changeVisibilityOfPopupWindow(!isDropped());
+ break;
+ }
+ }
+ }
+
+ /**
+ * Checks if is dropped.
+ *
+ * @return <code>true</code> if the popup is visible and not dropped,
+ * <code>false</code> otherwise
+ */
+ private boolean isDropped() {
+ return !this.popup.isDisposed() && this.popup.getVisible();
+ }
+
+ /**
+ * Handle a popup event.
+ *
+ * @param event event to handle
+ */
+ private void handlePopupEvent(final Event event) {
+ switch (event.type) {
+ case SWT.Close:
+ event.doit = false;
+ changeVisibilityOfPopupWindow(false);
+ break;
+ case SWT.Deactivate:
+ changeVisibilityOfPopupWindow(false);
+ break;
+ case SWT.Dispose:
+ if (this.checkboxes != null) {
+ this.checkboxes.clear();
+ }
+ this.checkboxes = null;
+ break;
+ }
+
+ }
+
+ /**
+ * Display/Hide the popup window.
+ *
+ * @param show if <code>true</code>, displays the popup window. If
+ * <code>false</code>, hide the popup window
+ */
+ private void changeVisibilityOfPopupWindow(final boolean show) {
+ if (show == isDropped()) {
+ return;
+ }
+
+ if (!show) {
+ this.popup.setVisible(false);
+ if (!isDisposed()) {
+ this.text.setFocus();
+ }
+ return;
+ }
+
+ if (getShell() != this.popup.getParent()) {
+ this.popup.dispose();
+ this.popup = null;
+ createPopup();
+ }
+
+ final Point arrowRect = this.arrow.toDisplay(this.arrow.getSize().x - 5, this.arrow.getSize().y + this.arrow.getBorderWidth() - 3);
+ int x = arrowRect.x;
+ int y = arrowRect.y;
+
+ final Rectangle displayRect = getMonitor().getClientArea();
+ final Rectangle parentRect = getDisplay().map(getParent(), null, getBounds());
+ this.popup.pack();
+
+ final int width = this.popup.getBounds().width;
+
+ final int maxHeight = (2 * displayRect.height / 3);
+ int height = this.popup.getBounds().height;
+
+ if (height > maxHeight) {
+ height = maxHeight;
+ this.popup.setSize(width, height);
+ this.scrolledComposite.setMinHeight(this.preferredHeightOfPopup);
+ this.popup.layout(true);
+ }
+
+ if (y + height > displayRect.y + displayRect.height) {
+ y = parentRect.y - height;
+ if (y < 0) {
+ height += y;
+ y = parentRect.y - height + 5;
+ this.popup.setSize(width, height);
+ this.scrolledComposite.setMinHeight(this.preferredHeightOfPopup);
+ this.popup.layout(true);
+ }
+ }
+ if (x + width > displayRect.x + displayRect.width) {
+ x = displayRect.x + displayRect.width - width;
+ }
+
+ this.popup.setLocation(x, y);
+ this.popup.setVisible(true);
+ this.popup.setFocus();
+ }
+
+ /**
+ * Check if the elements attributes is not null.
+ *
+ * @exception NullPointerException if there is no item in the receiver
+ */
+ private void checkNullElement() {
+ if (this.elements == null) {
+ throw new NullPointerException("There is no element associated to this widget");
+ }
+ }
+
+ /**
+ * Check range.
+ *
+ * @param index the index
+ * @throws NullPointerException the null pointer exception
+ * @throws IllegalArgumentException the illegal argument exception
+ */
+ private void checkRange(final int index) throws NullPointerException {
+ checkNullElement();
+ if (index < 0 || index >= this.elements.size()) {
+ SWT.error(SWT.ERROR_INVALID_RANGE);
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceDefaultLabelProvider.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceDefaultLabelProvider.java
new file mode 100644
index 0000000..9bb6965
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceDefaultLabelProvider.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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.multiChoice;
+
+/**
+ * Default MultiChoiceLabelProvider that uses the toString() method to determine
+ * the content of a given element.
+ */
+public class MultiChoiceDefaultLabelProvider implements MultiChoiceLabelProvider {
+
+ /**
+ * Gets the text.
+ *
+ * @param element the element
+ * @return the text
+ * @see org.mihalis.opal.multiChoice.MultiChoiceLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(final Object element) {
+ return element == null ? "" : element.toString();
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceLabelProvider.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceLabelProvider.java
new file mode 100644
index 0000000..0a6404b
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceLabelProvider.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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.multiChoice;
+
+/**
+ * Classes which implement this interface provide methods that determine what to show in a MultiChoice control.
+ */
+public interface MultiChoiceLabelProvider {
+
+ /**
+ * Gets the text.
+ *
+ * @param element the element for which to provide the label text
+ * @return the text string used to label the element, or "" if there is no
+ * text label for the given object
+ */
+ String getText(Object element);
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceSelectionListener.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceSelectionListener.java
new file mode 100644
index 0000000..ca7f11f
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/multiChoice/MultiChoiceSelectionListener.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * 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.multiChoice;
+
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Classes which extend this abstract class provide methods that deal with the
+ * events that are generated when selection occurs in a MultiChoice control.
+ *
+ * @param <T> the generic type
+ * @see MultiChoiceSelectionEvent
+ */
+public abstract class MultiChoiceSelectionListener<T> implements SelectionListener {
+
+ /** The parent. */
+ private final MultiChoice<T> parent;
+
+ /**
+ * Instantiates a new multi choice selection listener.
+ *
+ * @param parent the parent
+ */
+ public MultiChoiceSelectionListener(final MultiChoice<T> parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Widget selected.
+ *
+ * @param e the e
+ * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public final void widgetSelected(final SelectionEvent e) {
+ final Button button = (Button) e.widget;
+ handle(this.parent, this.parent.getLastModified(), button.getSelection(), this.parent.getPopup());
+ }
+
+ /**
+ * Widget default selected.
+ *
+ * @param inutile the inutile
+ * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public final void widgetDefaultSelected(final SelectionEvent inutile) {
+ }
+
+ /**
+ * This method contains the code that is called when the selection has
+ * changed.
+ *
+ * @param parent MultiChoice responsible of the event
+ * @param receiver Object modified
+ * @param selected If <code>true</code>, the check box has been checked
+ * @param popup the popup window that contains all checkboxes
+ */
+ public abstract void handle(MultiChoice<T> parent, T receiver, boolean selected, Shell popup);
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/notify/Notifier.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/notify/Notifier.java
new file mode 100644
index 0000000..3679b8a
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/notify/Notifier.java
@@ -0,0 +1,350 @@
+/*******************************************************************************
+ * 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.notify;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+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.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+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;
+import org.mihalis.opal.notify.NotifierColorsFactory.NotifierTheme;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This class provides a notifier window, which is a window that appears in the bottom of the screen and slides.
+ */
+public class Notifier {
+
+ /** The Constant FONT_SIZE. */
+ private static final int FONT_SIZE = 10;
+
+ /** The Constant MAX_DURATION_FOR_OPENING. */
+ private static final int MAX_DURATION_FOR_OPENING = 500;
+
+ /** The Constant DISPLAY_TIME. */
+ private static final int DISPLAY_TIME = 4500;
+
+ /** The Constant FADE_TIMER. */
+ private static final int FADE_TIMER = 50;
+
+ /** The Constant FADE_OUT_STEP. */
+ private static final int FADE_OUT_STEP = 8;
+
+ /** The Constant STEP. */
+ private static final int STEP = 5;
+
+ /**
+ * Starts a notification. A window will appear in the bottom of the screen, then will disappear after 4.5 s
+ *
+ * @param title the title of the popup window
+ * @param text the text of the notification
+ *
+ */
+ public static void notify(final String title, final String text) {
+ notify(null, title, text, NotifierTheme.YELLOW_THEME);
+ }
+
+ /**
+ * Starts a notification. A window will appear in the bottom of the screen, then will disappear after 4.5 s
+ *
+ * @param image the image to display (if <code>null</code>, a default image is displayed)
+ * @param title the title of the popup window
+ * @param text the text of the notification
+ *
+ */
+ public static void notify(final Image image, final String title, final String text) {
+ notify(image, title, text, NotifierTheme.YELLOW_THEME);
+
+ }
+
+ /**
+ * Starts a notification. A window will appear in the bottom of the screen, then will disappear after 4.5 s
+ *
+ * @param title the title of the popup window
+ * @param text the text of the notification
+ * @param theme the graphical theme. If <code>null</code>, the yellow theme is used
+ *
+ * @see NotifierTheme
+ */
+ public static void notify(final String title, final String text, final NotifierTheme theme) {
+ notify(null, title, text, theme);
+ }
+
+ /**
+ * Starts a notification. A window will appear in the bottom of the screen, then will disappear after 4.5 s
+ *
+ * @param image the image to display (if <code>null</code>, a default image is displayed)
+ * @param title the title of the popup window
+ * @param text the text of the notification
+ * @param theme the graphical theme. If <code>null</code>, the yellow theme is used
+ *
+ * @see NotifierTheme
+ */
+ public static void notify(final Image image, final String title, final String text, final NotifierTheme theme) {
+ final Shell shell = createNotificationWindow(image, title, text, NotifierColorsFactory.getColorsForTheme(theme));
+ makeShellAppears(shell);
+ }
+
+ /**
+ * Creates a notification window.
+ *
+ * @param image image. If <code>null</code>, a default image is used
+ * @param title title, the title of the window
+ * @param text text of the window
+ * @param colors color set
+ * @return the notification window as a shell object
+ */
+ private static Shell createNotificationWindow(final Image image, final String title, final String text, final NotifierColors colors) {
+ final Shell shell = new Shell(SWT.NO_TRIM | SWT.NO_FOCUS | SWT.ON_TOP);
+ shell.setLayout(new GridLayout(2, false));
+ shell.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ createTitle(shell, title, colors);
+ createImage(shell, image);
+ createText(shell, text, colors);
+ createBackground(shell, colors);
+ createCloseAction(shell);
+
+ shell.addListener(SWT.Dispose, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ colors.dispose();
+ }
+ });
+
+ shell.pack();
+ shell.setMinimumSize(320, 100);
+ return shell;
+ }
+
+ /**
+ * Creates the title part of the window.
+ *
+ * @param shell the window
+ * @param title the title
+ * @param colors the color set
+ */
+ private static void createTitle(final Shell shell, final String title, final NotifierColors colors) {
+ final Label titleLabel = new Label(shell, SWT.NONE);
+ final GridData gdLabel = new GridData(GridData.BEGINNING, GridData.BEGINNING, true, false, 2, 1);
+ gdLabel.horizontalIndent = 40;
+ titleLabel.setLayoutData(gdLabel);
+ final Color titleColor = colors.titleColor;
+ titleLabel.setForeground(titleColor);
+
+ final Font titleFont = SWTGraphicUtil.buildFontFrom(titleLabel, SWT.BOLD, FONT_SIZE);
+ titleLabel.setFont(titleFont);
+ titleLabel.setText(title);
+ SWTGraphicUtil.addDisposer(shell, titleFont);
+ }
+
+ /**
+ * Creates the image part of the window.
+ *
+ * @param shell the window
+ * @param image the image
+ */
+ private static void createImage(final Shell shell, final Image image) {
+ final Label labelImage = new Label(shell, SWT.NONE);
+ final GridData gdImage = new GridData(GridData.CENTER, GridData.BEGINNING, false, true);
+ gdImage.horizontalIndent = 10;
+ labelImage.setLayoutData(gdImage);
+ if (image == null) {
+ final Image temp = SWTGraphicUtil.createImageFromFile("images/information.png");
+ labelImage.setImage(temp);
+ SWTGraphicUtil.addDisposer(shell, temp);
+ } else {
+ labelImage.setImage(image);
+ }
+
+ }
+
+ /**
+ * Creates the text part of the window.
+ *
+ * @param shell the window
+ * @param text the text
+ * @param colors the color set
+ */
+ private static void createText(final Shell shell, final String text, final NotifierColors colors) {
+ final StyledText textLabel = new StyledText(shell, SWT.WRAP | SWT.READ_ONLY);
+ final GridData gdText = new GridData(GridData.FILL, GridData.FILL, true, true);
+ gdText.horizontalIndent = 15;
+ textLabel.setLayoutData(gdText);
+ textLabel.setEnabled(false);
+ final Font textFont = SWTGraphicUtil.buildFontFrom(textLabel, SWT.NONE, 10);
+ textLabel.setFont(textFont);
+
+ final Color textColor = colors.textColor;
+ textLabel.setForeground(textColor);
+
+ textLabel.setText(text);
+ SWTGraphicUtil.applyHTMLFormating(textLabel);
+
+ SWTGraphicUtil.addDisposer(shell, textFont);
+ }
+
+ /**
+ * Creates the background of the window.
+ *
+ * @param shell the window
+ * @param colors the color set of the window
+ */
+ private static void createBackground(final Shell shell, final NotifierColors colors) {
+ shell.addListener(SWT.Resize, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ final Rectangle rect = shell.getClientArea();
+ final Image newImage = new Image(Display.getDefault(), Math.max(1, rect.width), rect.height);
+ final GC gc = new GC(newImage);
+ gc.setAntialias(SWT.ON);
+
+ final Color borderColor = colors.borderColor;
+ final Color fillColor1 = colors.leftColor;
+ final Color fillColor2 = colors.rightColor;
+
+ gc.setBackground(borderColor);
+ gc.fillRoundRectangle(0, 0, rect.width, rect.height, 8, 8);
+
+ gc.setBackground(fillColor1);
+ gc.fillRoundRectangle(1, 1, rect.width - 2, rect.height - 2, 8, 8);
+
+ gc.setBackground(fillColor2);
+ gc.fillRoundRectangle(30, 1, rect.width - 32, rect.height - 2, 8, 8);
+ gc.fillRectangle(30, 1, 10, rect.height - 2);
+
+ final Image closeImage = SWTGraphicUtil.createImageFromFile("images/close.png");
+ gc.drawImage(closeImage, rect.width - 21, 13);
+
+ gc.dispose();
+ closeImage.dispose();
+
+ shell.setBackgroundImage(newImage);
+
+ }
+ });
+
+ }
+
+ /**
+ * Make shell appears.
+ *
+ * @param shell shell that will appear
+ */
+ private static void makeShellAppears(final Shell shell) {
+ if (shell == null || shell.isDisposed()) {
+ return;
+ }
+
+ final Rectangle clientArea = Display.getDefault().getPrimaryMonitor().getClientArea();
+ final int startX = clientArea.x + clientArea.width - shell.getSize().x;
+
+ final int stepForPosition = MAX_DURATION_FOR_OPENING / shell.getSize().y * STEP;
+ final int stepForAlpha = STEP * 255 / shell.getSize().y;
+
+ final int lastPosition = clientArea.y + clientArea.height - shell.getSize().y;
+
+ shell.setAlpha(0);
+ shell.setLocation(startX, clientArea.y + clientArea.height);
+ shell.open();
+
+ shell.getDisplay().timerExec(stepForPosition, new Runnable() {
+
+ @Override
+ public void run() {
+
+ if (shell == null || shell.isDisposed()) {
+ return;
+ }
+
+ shell.setLocation(startX, shell.getLocation().y - STEP);
+ shell.setAlpha(shell.getAlpha() + stepForAlpha);
+ if (shell.getLocation().y >= lastPosition) {
+ shell.getDisplay().timerExec(stepForPosition, this);
+ } else {
+ shell.setAlpha(255);
+ Display.getDefault().timerExec(DISPLAY_TIME, fadeOut(shell, false));
+ }
+ }
+ });
+
+ }
+
+ /**
+ * Fade out.
+ *
+ * @param shell shell that will disappear
+ * @param fast if true, the fading is much faster
+ * @return a runnable
+ */
+ private static Runnable fadeOut(final Shell shell, final boolean fast) {
+ return new Runnable() {
+
+ @Override
+ public void run() {
+ if (shell == null || shell.isDisposed()) {
+ return;
+ }
+
+ int currentAlpha = shell.getAlpha();
+ currentAlpha -= FADE_OUT_STEP * (fast ? 8 : 1);
+
+ if (currentAlpha <= 0) {
+ shell.setAlpha(0);
+ shell.dispose();
+ return;
+ }
+
+ shell.setAlpha(currentAlpha);
+
+ Display.getDefault().timerExec(FADE_TIMER, this);
+
+ }
+
+ };
+ }
+
+ /**
+ * Add a listener to the shell in order to handle the clicks on the close
+ * button.
+ *
+ * @param shell associated shell
+ */
+ private static void createCloseAction(final Shell shell) {
+ shell.addListener(SWT.MouseUp, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ final Rectangle rect = shell.getClientArea();
+ final int xUpperLeftCorner = rect.width - 21;
+ final int yUpperLeftCorner = 13;
+
+ if (event.x >= xUpperLeftCorner && event.x <= xUpperLeftCorner + 8 && event.y >= yUpperLeftCorner && event.y <= yUpperLeftCorner + 8) {
+ Display.getDefault().timerExec(0, fadeOut(shell, true));
+ }
+
+ }
+ });
+
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/notify/NotifierColors.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/notify/NotifierColors.java
new file mode 100644
index 0000000..3c0f04c
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/notify/NotifierColors.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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.notify;
+
+import org.eclipse.swt.graphics.Color;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This class is a simple POJO that holds colors used by the Notifier widget.
+ */
+class NotifierColors {
+
+ /** The title color. */
+ Color titleColor;
+
+ /** The text color. */
+ Color textColor;
+
+ /** The border color. */
+ Color borderColor;
+
+ /** The left color. */
+ Color leftColor;
+
+ /** The right color. */
+ Color rightColor;
+
+ /**
+ * Dispose.
+ */
+ void dispose() {
+ SWTGraphicUtil.safeDispose(this.titleColor);
+ SWTGraphicUtil.safeDispose(this.borderColor);
+ SWTGraphicUtil.safeDispose(this.leftColor);
+ SWTGraphicUtil.safeDispose(this.rightColor);
+ SWTGraphicUtil.safeDispose(this.textColor);
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/notify/NotifierColorsFactory.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/notify/NotifierColorsFactory.java
new file mode 100644
index 0000000..5e67659
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/notify/NotifierColorsFactory.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * 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.notify;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * This class creates the colors associated to a given theme.
+ */
+public class NotifierColorsFactory {
+
+ /**
+ * The Enum NotifierTheme.
+ */
+ public enum NotifierTheme {
+
+ /** The yellow theme. */
+ YELLOW_THEME,
+ /** The gray theme. */
+ GRAY_THEME,
+ /** The blue theme. */
+ BLUE_THEME
+ };
+
+ /**
+ * Constructor.
+ */
+ private NotifierColorsFactory() {
+
+ }
+
+ /**
+ * Gets the colors for theme.
+ *
+ * @param theme a theme for the notifier widget
+ * @return the color set for the given theme
+ */
+ static NotifierColors getColorsForTheme(final NotifierTheme theme) {
+ final NotifierColors colors = new NotifierColors();
+ switch (theme) {
+ case BLUE_THEME:
+ colors.textColor = new Color(Display.getDefault(), 4, 64, 140);
+ colors.titleColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ colors.borderColor = new Color(Display.getDefault(), 153, 188, 232);
+ colors.leftColor = new Color(Display.getDefault(), 210, 225, 244);
+ colors.rightColor = new Color(Display.getDefault(), 182, 207, 238);
+ break;
+ case GRAY_THEME:
+ colors.textColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ colors.titleColor = Display.getDefault().getSystemColor(SWT.COLOR_DARK_RED);
+ colors.borderColor = new Color(Display.getDefault(), 208, 208, 208);
+ colors.leftColor = new Color(Display.getDefault(), 255, 255, 255);
+ colors.rightColor = new Color(Display.getDefault(), 208, 208, 208);
+ break;
+ default:
+ colors.textColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ colors.titleColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ colors.borderColor = new Color(Display.getDefault(), 218, 178, 85);
+ colors.leftColor = new Color(Display.getDefault(), 220, 220, 160);
+ colors.rightColor = new Color(Display.getDefault(), 255, 255, 191);
+ break;
+ }
+ return colors;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/AbstractButtonRenderer.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/AbstractButtonRenderer.java
new file mode 100644
index 0000000..5ccb848
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/AbstractButtonRenderer.java
@@ -0,0 +1,532 @@
+/*******************************************************************************
+ * 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.obutton;
+
+import org.eclipse.swt.SWT;
+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.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.utils.AdvancedPath;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This class is an abstract button renderer used for default, red, orange,
+ * green and purple themes.
+ */
+public abstract class AbstractButtonRenderer implements ButtonRenderer {
+
+ /** The Constant ARROW_RIGHT_IMAGE. */
+ private static final String ARROW_RIGHT_IMAGE = "images/arrow_right.png";
+
+ /** The Constant ARROW_LEFT_IMAGE. */
+ private static final String ARROW_LEFT_IMAGE = "images/arrow_left.png";
+
+ /** The Constant ARROW_DOWN_IMAGE. */
+ private static final String ARROW_DOWN_IMAGE = "images/arrow_down.png";
+
+ /** The Constant ARROW_UP_IMAGE. */
+ private static final String ARROW_UP_IMAGE = "images/arrow_up.png";
+
+ /** The Constant RADIUS_VALUE. */
+ private static final int RADIUS_VALUE = 10;
+
+ /** The Constant DISABLED_FONT_COLOR. */
+ private static final Color DISABLED_FONT_COLOR = SWTGraphicUtil.getColorSafely(119, 119, 119);
+
+ /** The Constant DISABLED_SECOND_BACKGROUND_COLOR. */
+ private static final Color DISABLED_SECOND_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(220, 220, 220);
+
+ /** The Constant DISABLED_FIRST_BACKGROUND_COLOR. */
+ private static final Color DISABLED_FIRST_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(237, 237, 237);
+
+ /** The onclick. */
+ private ButtonConfiguration normal, hover, disabled, selected, onclick;
+
+ /** The gc. */
+ private GC gc;
+
+ /** The configuration. */
+ private ButtonConfiguration configuration;
+
+ /** The gap on clic. */
+ private int gapOnClic;
+
+ /** The parent. */
+ protected OButton parent;
+
+ /** The image up. */
+ private Image imageUp;
+
+ /** The image down. */
+ private Image imageDown;
+
+ /** The image left. */
+ private Image imageLeft;
+
+ /** The image right. */
+ private Image imageRight;
+
+ /** The disabled image. */
+ private Image disabledImage;
+
+ /** The Constant MARGIN. */
+ private static final int MARGIN = 5;
+
+ /** The Constant GAP_ON_CLIC. */
+ private static final int GAP_ON_CLIC = 2;
+
+ /**
+ * Constructor.
+ */
+ protected AbstractButtonRenderer() {
+ initButtonConfiguration();
+ createArrows();
+ createDisabledImage();
+ }
+
+ /**
+ * Inits the button configuration.
+ */
+ private void initButtonConfiguration() {
+ normal = createNormalConfiguration();
+ hover = createHoverConfiguration();
+ disabled = createDisabledConfiguration();
+ selected = createSelectedConfiguration();
+ onclick = createOnClickConfiguration();
+ }
+
+ /**
+ * Creates the normal configuration.
+ *
+ * @return the configuration when the button is not clicked, enabled, not
+ * selected, and the mouse is not hover
+ */
+ protected ButtonConfiguration createNormalConfiguration() {
+ final ButtonConfiguration configuration = new ButtonConfiguration();
+ configuration.setCornerRadius(10);
+ configuration.setFont(Display.getDefault().getSystemFont()).setFontColor(getFontColor());
+ configuration.setGradientDirection(SWT.VERTICAL);
+ configuration.setBackgroundColor(getFirstBackgroundColor());
+ configuration.setSecondBackgroundColor(getSecondBackgroundColor());
+ return configuration;
+ }
+
+ /**
+ * Gets the font color.
+ *
+ * @return the font color
+ */
+ protected abstract Color getFontColor();
+
+ /**
+ * Gets the first background color.
+ *
+ * @return the first background color
+ */
+ protected abstract Color getFirstBackgroundColor();
+
+ /**
+ * Gets the second background color.
+ *
+ * @return the second background color
+ */
+ protected abstract Color getSecondBackgroundColor();
+
+ /**
+ * Creates the hover configuration.
+ *
+ * @return the configuration when the mouse is hover
+ */
+ protected ButtonConfiguration createHoverConfiguration() {
+ final ButtonConfiguration configuration = new ButtonConfiguration();
+ configuration.setCornerRadius(10);
+ configuration.setFont(Display.getDefault().getSystemFont()).setFontColor(getFontColor());
+ configuration.setGradientDirection(SWT.VERTICAL);
+ configuration.setBackgroundColor(getSecondBackgroundColor());
+ configuration.setSecondBackgroundColor(getFirstBackgroundColor());
+ return configuration;
+ }
+
+ /**
+ * Creates the disabled configuration.
+ *
+ * @return the configuration when the button is disabled
+ */
+ protected ButtonConfiguration createDisabledConfiguration() {
+ final ButtonConfiguration configuration = new ButtonConfiguration();
+ configuration.setCornerRadius(RADIUS_VALUE);
+ configuration.setFont(Display.getDefault().getSystemFont()).setFontColor(DISABLED_FONT_COLOR);
+ configuration.setGradientDirection(SWT.VERTICAL);
+ configuration.setBackgroundColor(DISABLED_FIRST_BACKGROUND_COLOR);
+ configuration.setSecondBackgroundColor(DISABLED_SECOND_BACKGROUND_COLOR);
+ return configuration;
+ }
+
+ /**
+ * Creates the selected configuration.
+ *
+ * @return the configuration when the button is selected
+ */
+ protected ButtonConfiguration createSelectedConfiguration() {
+ return createHoverConfiguration();
+ }
+
+ /**
+ * Creates the on click configuration.
+ *
+ * @return the configuration when the button is clicked
+ */
+ protected ButtonConfiguration createOnClickConfiguration() {
+ return createHoverConfiguration();
+ }
+
+ /**
+ * Creates the arrows.
+ */
+ private void createArrows() {
+ final ClassLoader loader = org.mihalis.opal.obutton.AbstractButtonRenderer.class.getClassLoader();
+ imageUp = new Image(Display.getCurrent(), loader.getResourceAsStream(ARROW_UP_IMAGE));
+ imageDown = new Image(Display.getCurrent(), loader.getResourceAsStream(ARROW_DOWN_IMAGE));
+ imageLeft = new Image(Display.getCurrent(), loader.getResourceAsStream(ARROW_LEFT_IMAGE));
+ imageRight = new Image(Display.getCurrent(), loader.getResourceAsStream(ARROW_RIGHT_IMAGE));
+
+ Display.getCurrent().addListener(SWT.Dispose, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ imageUp.dispose();
+ imageDown.dispose();
+ imageLeft.dispose();
+ imageRight.dispose();
+ }
+ });
+ }
+
+ /**
+ * Creates the disabled image.
+ *
+ * @see org.mihalis.opal.obutton.ButtonRenderer#createDisabledImage()
+ */
+ @Override
+ public void createDisabledImage() {
+ if (disabledImage != null && !disabledImage.isDisposed()) {
+ disabledImage.dispose();
+ }
+ if (parent == null || parent.getImage() == null) {
+ disabledImage = null;
+ } else {
+ disabledImage = new Image(parent.getDisplay(), parent.getImage(), SWT.IMAGE_DISABLE);
+ parent.addListener(SWT.Dispose, new Listener() {
+ @Override
+ public void handleEvent(final Event e) {
+ if (!disabledImage.isDisposed()) {
+ disabledImage.dispose();
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Dispose.
+ *
+ * @see org.mihalis.opal.obutton.ButtonRenderer#dispose()
+ */
+ @Override
+ public void dispose() {
+ }
+
+ /**
+ * Draw button when mouse hover.
+ *
+ * @param gc the gc
+ * @param parent the parent
+ * @see org.mihalis.opal.obutton.ButtonRenderer#drawButtonWhenMouseHover(org.eclipse.swt.graphics.GC,
+ * org.mihalis.opal.obutton.OButton)
+ */
+ @Override
+ public void drawButtonWhenMouseHover(final GC gc, final OButton parent) {
+ this.gc = gc;
+ configuration = hover;
+ gapOnClic = 0;
+ this.parent = parent;
+ draw();
+ }
+
+ /**
+ * Draw.
+ */
+ private void draw() {
+ gc.setAdvanced(true);
+ gc.setAntialias(SWT.ON);
+ drawBackground();
+ int xPosition = computeStartingPosition();
+ xPosition += drawImage(xPosition);
+ if (parent.getText() != null) {
+ drawText(xPosition);
+ }
+ }
+
+ /**
+ * Draw background.
+ */
+ private void drawBackground() {
+ final AdvancedPath path = createClipping();
+ if (path.isDisposed()) {
+ return;
+ }
+ gc.setClipping(path);
+ gc.setForeground(configuration.getBackgroundColor());
+ gc.setBackground(configuration.getSecondBackgroundColor());
+ gc.fillGradientRectangle(0, gapOnClic, parent.getWidth(), parent.getHeight() - GAP_ON_CLIC, configuration.getGradientDirection() == SWT.VERTICAL);
+ gc.setClipping((Rectangle) null);
+ path.dispose();
+ }
+
+ /**
+ * Creates the clipping.
+ *
+ * @return the advanced path
+ */
+ private AdvancedPath createClipping() {
+ final AdvancedPath path = new AdvancedPath(parent.getDisplay());
+ path.addRoundRectangle(0, gapOnClic, parent.getWidth(), parent.getHeight() - GAP_ON_CLIC, configuration.getCornerRadius(), configuration.getCornerRadius());
+ return path;
+ }
+
+ /**
+ * Compute starting position.
+ *
+ * @return the int
+ */
+ private int computeStartingPosition() {
+ final int widthOfTextAndImage = computeSizeOfTextAndImages().x;
+ switch (parent.alignment) {
+ case SWT.CENTER:
+ return (parent.getWidth() - widthOfTextAndImage) / 2;
+ case SWT.RIGHT:
+ return parent.getWidth() - widthOfTextAndImage - MARGIN;
+ default:
+ return MARGIN;
+ }
+ }
+
+ /**
+ * Draw image.
+ *
+ * @param xPosition the x position
+ * @return the int
+ */
+ private int drawImage(final int xPosition) {
+ final Image image = extractImage();
+
+ if (image == null) {
+ return 0;
+ }
+
+ final int yPosition = (parent.getHeight() - image.getBounds().height - GAP_ON_CLIC) / 2;
+ gc.drawImage(image, xPosition, yPosition + gapOnClic);
+ return image.getBounds().width + MARGIN;
+ }
+
+ /**
+ * Extract image.
+ *
+ * @return the image
+ */
+ private Image extractImage() {
+ if ((parent.getStyle() & SWT.ARROW) != 0) {
+ if ((parent.getStyle() & SWT.DOWN) != 0) {
+ return imageDown;
+ }
+ if ((parent.getStyle() & SWT.UP) != 0) {
+ return imageUp;
+ }
+ if ((parent.getStyle() & SWT.LEFT) != 0) {
+ return imageLeft;
+ }
+ if ((parent.getStyle() & SWT.RIGHT) != 0) {
+ return imageRight;
+ }
+ }
+
+ if (parent.getImage() == null) {
+ return null;
+ }
+
+ final Image image;
+ if (!parent.isEnabled()) {
+ image = disabledImage;
+ } else {
+ image = parent.getImage();
+ }
+
+ return image;
+ }
+
+ /**
+ * Draw text.
+ *
+ * @param xPosition the x position
+ */
+ private void drawText(final int xPosition) {
+ gc.setFont(configuration.getFont());
+ gc.setForeground(configuration.getFontColor());
+
+ final Point textSize = gc.stringExtent(parent.getText());
+ final int yPosition = (parent.getHeight() - textSize.y - GAP_ON_CLIC) / 2;
+
+ gc.drawText(parent.getText(), xPosition, yPosition + gapOnClic, true);
+ }
+
+ /**
+ * Draw button when disabled.
+ *
+ * @param gc the gc
+ * @param parent the parent
+ * @see org.mihalis.opal.obutton.ButtonRenderer#drawButtonWhenDisabled(org.eclipse.swt.graphics.GC,
+ * org.mihalis.opal.obutton.OButton)
+ */
+ @Override
+ public void drawButtonWhenDisabled(final GC gc, final OButton parent) {
+ this.gc = gc;
+ configuration = disabled;
+ gapOnClic = 0;
+ this.parent = parent;
+ draw();
+ }
+
+ /**
+ * Draw button when selected.
+ *
+ * @param gc the gc
+ * @param parent the parent
+ * @see org.mihalis.opal.obutton.ButtonRenderer#drawButtonWhenSelected(org.eclipse.swt.graphics.GC,
+ * org.mihalis.opal.obutton.OButton)
+ */
+ @Override
+ public void drawButtonWhenSelected(final GC gc, final OButton parent) {
+ this.gc = gc;
+ configuration = selected;
+ gapOnClic = 0;
+ this.parent = parent;
+ draw();
+ }
+
+ /**
+ * Draw button.
+ *
+ * @param gc the gc
+ * @param parent the parent
+ * @see org.mihalis.opal.obutton.ButtonRenderer#drawButton(org.eclipse.swt.graphics.GC,
+ * org.mihalis.opal.obutton.OButton)
+ */
+ @Override
+ public void drawButton(final GC gc, final OButton parent) {
+ this.gc = gc;
+ configuration = normal;
+ gapOnClic = 0;
+ this.parent = parent;
+ draw();
+ }
+
+ /**
+ * Draw button when clicked.
+ *
+ * @param gc the gc
+ * @param parent the parent
+ * @see org.mihalis.opal.obutton.ButtonRenderer#drawButtonWhenClicked(org.eclipse.swt.graphics.GC,
+ * org.mihalis.opal.obutton.OButton)
+ */
+ @Override
+ public void drawButtonWhenClicked(final GC gc, final OButton parent) {
+ this.gc = gc;
+ configuration = onclick;
+ gapOnClic = GAP_ON_CLIC;
+ this.parent = parent;
+ draw();
+ }
+
+ /**
+ * Compute size.
+ *
+ * @param button the button
+ * @param wHint the w hint
+ * @param hHint the h hint
+ * @param changed the changed
+ * @return the point
+ * @see org.mihalis.opal.obutton.ButtonRenderer#computeSize(org.mihalis.opal.obutton.OButton,
+ * int, int, boolean)
+ */
+ @Override
+ public Point computeSize(final OButton button, final int wHint, final int hHint, final boolean changed) {
+ parent = button;
+ final Point sizeOfTextAndImages = computeSizeOfTextAndImages();
+ return new Point(2 * MARGIN + sizeOfTextAndImages.x, 2 * MARGIN + sizeOfTextAndImages.y + GAP_ON_CLIC);
+ }
+
+ /**
+ * Compute size of text and images.
+ *
+ * @return the point
+ */
+ private Point computeSizeOfTextAndImages() {
+ int width = 0, height = 0;
+ final boolean textNotEmpty = parent.getText() != null && !parent.getText().equals("");
+
+ if (textNotEmpty) {
+ final GC gc = new GC(parent);
+ if (configuration == null) {
+ gc.setFont(parent.getFont());
+ } else {
+ gc.setFont(configuration.getFont());
+ }
+
+ final Point extent = gc.stringExtent(parent.getText());
+ gc.dispose();
+ width += extent.x;
+ height = extent.y;
+ }
+
+ final Point imageSize = new Point(-1, -1);
+ computeImageSize(extractImage(), imageSize);
+
+ if (imageSize.x != -1) {
+ width += imageSize.x;
+ height = Math.max(imageSize.y, height);
+ if (textNotEmpty) {
+ width += MARGIN;
+ }
+ }
+ return new Point(width, height);
+ }
+
+ /**
+ * Compute image size.
+ *
+ * @param image the image
+ * @param imageSize the image size
+ */
+ private void computeImageSize(final Image image, final Point imageSize) {
+ if (image == null) {
+ return;
+ }
+ final Rectangle imageBounds = image.getBounds();
+ imageSize.x = Math.max(imageBounds.width, imageSize.x);
+ imageSize.y = Math.max(imageBounds.height, imageSize.y);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/ButtonConfiguration.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/ButtonConfiguration.java
new file mode 100644
index 0000000..0f99c1d
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/ButtonConfiguration.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * 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.obutton;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+
+/**
+ * This class is a POJO used to configure a OButton widget.
+ */
+public class ButtonConfiguration {
+
+ /** The font. */
+ private Font font;
+
+ /** The font color. */
+ private Color fontColor;
+
+ /** The corner radius. */
+ private int cornerRadius;
+
+ /** The gradient direction. */
+ private int gradientDirection;
+
+ /** The background color. */
+ private Color backgroundColor;
+
+ /** The second background color. */
+ private Color secondBackgroundColor;
+
+ /**
+ * Gets the font.
+ *
+ * @return the font
+ */
+ public Font getFont() {
+ return this.font;
+ }
+
+ /**
+ * Gets the font color.
+ *
+ * @return the fontColor
+ */
+ public Color getFontColor() {
+ return this.fontColor;
+ }
+
+ /**
+ * Gets the corner radius.
+ *
+ * @return the cornerRadius
+ */
+ public int getCornerRadius() {
+ return this.cornerRadius;
+ }
+
+ /**
+ * Gets the gradient direction.
+ *
+ * @return the gradientDirection
+ */
+ public int getGradientDirection() {
+ return this.gradientDirection;
+ }
+
+ /**
+ * Gets the background color.
+ *
+ * @return the backgroundColor
+ */
+ public Color getBackgroundColor() {
+ return this.backgroundColor;
+ }
+
+ /**
+ * Gets the second background color.
+ *
+ * @return the secondBackgroundColor
+ */
+ public Color getSecondBackgroundColor() {
+ return this.secondBackgroundColor;
+ }
+
+ /**
+ * Sets the font.
+ *
+ * @param font the font to set
+ * @return the button configuration
+ */
+ public ButtonConfiguration setFont(final Font font) {
+ if (font != null && font.isDisposed()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.font = font;
+ return this;
+ }
+
+ /**
+ * Sets the font color.
+ *
+ * @param fontColor the fontColor to set
+ * @return the button configuration
+ */
+ public ButtonConfiguration setFontColor(final Color fontColor) {
+ if (fontColor != null && fontColor.isDisposed()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ this.fontColor = fontColor;
+ return this;
+ }
+
+ /**
+ * Sets the corner radius.
+ *
+ * @param cornerRadius the cornerRadius to set
+ * @return the button configuration
+ */
+ public ButtonConfiguration setCornerRadius(final int cornerRadius) {
+ this.cornerRadius = Math.max(0, cornerRadius);
+ return this;
+ }
+
+ /**
+ * Sets the gradient direction.
+ *
+ * @param gradientDirection the gradientDirection to set
+ * @return the button configuration
+ */
+ public ButtonConfiguration setGradientDirection(final int gradientDirection) {
+ if (gradientDirection != SWT.VERTICAL && gradientDirection != SWT.HORIZONTAL) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.gradientDirection = gradientDirection;
+ return this;
+ }
+
+ /**
+ * Sets the background color.
+ *
+ * @param backgroundColor the backgroundColor to set
+ * @return the button configuration
+ */
+ public ButtonConfiguration setBackgroundColor(final Color backgroundColor) {
+ if (backgroundColor != null && backgroundColor.isDisposed()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.backgroundColor = backgroundColor;
+ return this;
+ }
+
+ /**
+ * Sets the second background color.
+ *
+ * @param secondBackgroundColor the secondBackgroundColor to set
+ * @return the button configuration
+ */
+ public ButtonConfiguration setSecondBackgroundColor(final Color secondBackgroundColor) {
+ if (secondBackgroundColor != null && secondBackgroundColor.isDisposed()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.secondBackgroundColor = secondBackgroundColor;
+ return this;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/ButtonRenderer.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/ButtonRenderer.java
new file mode 100644
index 0000000..5400ef5
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/ButtonRenderer.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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.obutton;
+
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+
+/**
+ * This interface contains methods used to render a button.
+ */
+public interface ButtonRenderer {
+
+ /**
+ * Dispose the elements when the button is disposed.
+ */
+ void dispose();
+
+ /**
+ * Draw the button when the mouse is hover.
+ *
+ * @param gc Graphical context
+ * @param button button displayed
+ */
+ void drawButtonWhenMouseHover(GC gc, OButton button);
+
+ /**
+ * Draw the button when the button is disabled.
+ *
+ * @param gc Graphical context
+ * @param button button displayed
+ */
+ void drawButtonWhenDisabled(GC gc, OButton button);
+
+ /**
+ * Draw the button when the button (toggle button) is selected.
+ *
+ * @param gc Graphical context
+ * @param button button displayed
+ */
+ void drawButtonWhenSelected(GC gc, OButton button);
+
+ /**
+ * Draw button.
+ *
+ * @param gc the gc
+ * @param button the button
+ */
+ void drawButton(GC gc, OButton button);
+
+ /**
+ * Draw the button when the button is clicked.
+ *
+ * @param gc Graphical context
+ * @param parent the parent
+ */
+ void drawButtonWhenClicked(GC gc, OButton parent);
+
+ /**
+ * Compute the size of the button.
+ *
+ * @param button button associated to this renderer
+ * @param wHint the width hint (can be <code>SWT.DEFAULT</code>)
+ * @param hHint the height hint (can be <code>SWT.DEFAULT</code>)
+ * @param changed <code>true</code> if the control's contents have changed,
+ * and <code>false</code> otherwise
+ * @return the size of the button
+ */
+ Point computeSize(OButton button, int wHint, int hHint, boolean changed);
+
+ /**
+ * Create disabled image.
+ */
+ void createDisabledImage();
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/DefaultButtonRenderer.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/DefaultButtonRenderer.java
new file mode 100644
index 0000000..ea993d5
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/DefaultButtonRenderer.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * 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.obutton;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This is the default button renderer.
+ */
+public class DefaultButtonRenderer extends AbstractButtonRenderer {
+
+ /** The instance. */
+ private static DefaultButtonRenderer instance;
+
+ /** The Constant FIRST_BACKGROUND_COLOR. */
+ private static final Color FIRST_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(121, 187, 255);
+
+ /** The Constant SECOND_BACKGROUND_COLOR. */
+ private static final Color SECOND_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(56, 142, 229);
+
+ /**
+ * Instantiates a new default button renderer.
+ */
+ private DefaultButtonRenderer() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getFontColor()
+ */
+ @Override
+ protected Color getFontColor() {
+ return Display.getDefault().getSystemColor(SWT.COLOR_WHITE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getFirstBackgroundColor()
+ */
+ @Override
+ protected Color getFirstBackgroundColor() {
+ return FIRST_BACKGROUND_COLOR;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getSecondBackgroundColor()
+ */
+ @Override
+ protected Color getSecondBackgroundColor() {
+ return SECOND_BACKGROUND_COLOR;
+ }
+
+ /**
+ * Gets the single instance of DefaultButtonRenderer.
+ *
+ * @return single instance of DefaultButtonRenderer
+ */
+ public static DefaultButtonRenderer getInstance() {
+ if (instance == null) {
+ instance = new DefaultButtonRenderer();
+ }
+ return instance;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/GreenButtonRenderer.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/GreenButtonRenderer.java
new file mode 100644
index 0000000..11f5bd3
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/GreenButtonRenderer.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * 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.obutton;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This is the green theme button renderer.
+ */
+public class GreenButtonRenderer extends AbstractButtonRenderer {
+
+ /** The instance. */
+ private static GreenButtonRenderer instance;
+
+ /** The Constant FIRST_BACKGROUND_COLOR. */
+ private static final Color FIRST_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(119, 212, 42);
+
+ /** The Constant SECOND_BACKGROUND_COLOR. */
+ private static final Color SECOND_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(38, 138, 22);
+
+ /**
+ * Instantiates a new green button renderer.
+ */
+ private GreenButtonRenderer() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getFontColor()
+ */
+ @Override
+ protected Color getFontColor() {
+ return Display.getDefault().getSystemColor(SWT.COLOR_WHITE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getFirstBackgroundColor()
+ */
+ @Override
+ protected Color getFirstBackgroundColor() {
+ return FIRST_BACKGROUND_COLOR;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getSecondBackgroundColor()
+ */
+ @Override
+ protected Color getSecondBackgroundColor() {
+ return SECOND_BACKGROUND_COLOR;
+ }
+
+ /**
+ * Gets the single instance of GreenButtonRenderer.
+ *
+ * @return single instance of GreenButtonRenderer
+ */
+ public static GreenButtonRenderer getInstance() {
+ if (instance == null) {
+ instance = new GreenButtonRenderer();
+ }
+ return instance;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/OButton.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/OButton.java
new file mode 100644
index 0000000..35041c4
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/OButton.java
@@ -0,0 +1,653 @@
+/*******************************************************************************
+ * 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.obutton;
+
+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.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.eclipse.swt.widgets.Widget;
+
+/**
+ * Instances of this class represent a selectable user interface object that issues notification when pressed and released.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>ARROW, PUSH, TOGGLE</dd>
+ * <dd>UP, DOWN, LEFT, RIGHT, CENTER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles ARROW, PUSH and TOGGLE may be specified.
+ * </p>
+ * <p>
+ * Note: Only one of the styles LEFT, RIGHT, and CENTER may be specified.
+ * </p>
+ * <p>
+ * Note: Only one of the styles UP, DOWN, LEFT, and RIGHT may be specified when the ARROW style is specified.
+ * </p>
+ */
+public class OButton extends Canvas {
+
+ /** The Constant IS_BUTTON_PRESSED. */
+ private static final String IS_BUTTON_PRESSED = OButton.class.toString() + "_pressed";
+
+ /** The selection listeners. */
+ private final List<SelectionListener> selectionListeners;
+
+ /** The alignment. */
+ int alignment = SWT.LEFT;
+
+ /** The button renderer. */
+ private ButtonRenderer buttonRenderer;
+
+ /** The selected. */
+ boolean selected;
+
+ /** The hover. */
+ boolean hover;
+
+ /** The text. */
+ String text;
+
+ /** The image. */
+ Image image;
+
+ /** The width. */
+ private int width;
+
+ /** The height. */
+ private int height;
+
+ /** The clicked. */
+ private boolean clicked;
+
+ /**
+ * 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#ARROW
+ * @see SWT#CHECK
+ * @see SWT#PUSH
+ * @see SWT#RADIO
+ * @see SWT#TOGGLE
+ * @see SWT#FLAT
+ * @see SWT#UP
+ * @see SWT#DOWN
+ * @see SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#CENTER
+ * @see Widget#checkSubclass
+ * @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 OButton(final Composite parent, final int style) {
+ super(parent, checkStyle(style) | SWT.DOUBLE_BUFFERED);
+ this.selectionListeners = new ArrayList<SelectionListener>();
+ this.buttonRenderer = DefaultButtonRenderer.getInstance();
+ this.width = this.height = -1;
+ addListeners();
+ }
+
+ /**
+ * Check style.
+ *
+ * @param style the style
+ * @return the int
+ */
+ private static int checkStyle(int style) {
+ style = checkBits(style, SWT.PUSH, SWT.ARROW, SWT.TOGGLE, 0);
+ if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
+ return checkBits(style, SWT.CENTER, SWT.LEFT, SWT.RIGHT, 0);
+ }
+ if ((style & SWT.ARROW) != 0) {
+ return checkBits(style, SWT.UP, SWT.DOWN, SWT.LEFT, SWT.RIGHT);
+ }
+ return style;
+ }
+
+ /**
+ * Check bits.
+ *
+ * @param style the style
+ * @param int0 the int0
+ * @param int1 the int1
+ * @param int2 the int2
+ * @param int3 the int3
+ * @return the int
+ */
+ private static int checkBits(int style, final int int0, final int int1, final int int2, final int int3) {
+ final int mask = int0 | int1 | int2 | int3;
+ 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;
+ }
+ if ((style & int3) != 0) {
+ style = style & ~mask | int3;
+ }
+ return style;
+ }
+
+ /**
+ * Adds the listeners.
+ */
+ private void addListeners() {
+ final Listener listener = new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ switch (event.type) {
+ case SWT.MouseEnter:
+ OButton.this.hover = true;
+ redraw();
+ update();
+ break;
+ case SWT.MouseExit:
+ OButton.this.hover = false;
+ redraw();
+ update();
+ break;
+ case SWT.MouseDown:
+ OButton.this.clicked = true;
+ OButton.this.setData(IS_BUTTON_PRESSED, "*");
+ redraw();
+ update();
+ break;
+ case SWT.MouseUp:
+ if (OButton.this.getData(IS_BUTTON_PRESSED) == null) {
+ return;
+ }
+ OButton.this.setData(IS_BUTTON_PRESSED, null);
+ OButton.this.clicked = false;
+ OButton.this.selected = !OButton.this.selected;
+ redraw();
+ update();
+ fireSelectionEvent();
+ break;
+ case SWT.Paint:
+ handlePaintEvent(event);
+ break;
+ case SWT.KeyDown:
+ if (event.keyCode == SWT.TAB) {
+ if (event.stateMask == SWT.SHIFT) {
+ OButton.this.traverse(SWT.TRAVERSE_TAB_PREVIOUS);
+ } else {
+ OButton.this.traverse(SWT.TRAVERSE_TAB_NEXT);
+ }
+ }
+ break;
+ case SWT.Dispose:
+ OButton.this.buttonRenderer.dispose();
+ break;
+
+ }
+
+ }
+ };
+
+ final int[] events = new int[] { SWT.MouseEnter, SWT.MouseExit, SWT.MouseDown, SWT.MouseUp, SWT.Paint, SWT.Dispose };
+ for (final int event : events) {
+ addListener(event, listener);
+ }
+ }
+
+ /**
+ * Fire selection event.
+ */
+ protected void fireSelectionEvent() {
+ final Event event = new Event();
+ event.widget = this;
+ event.display = getDisplay();
+ event.type = SWT.Selection;
+ for (final SelectionListener selectionListener : this.selectionListeners) {
+ selectionListener.widgetSelected(new SelectionEvent(event));
+ }
+ }
+
+ /**
+ * Handle paint event.
+ *
+ * @param event the event
+ */
+ private void handlePaintEvent(final Event event) {
+ if (!isEnabled()) {
+ this.buttonRenderer.drawButtonWhenDisabled(event.gc, this);
+ return;
+ }
+
+ if (this.clicked) {
+ this.buttonRenderer.drawButtonWhenClicked(event.gc, this);
+ return;
+ }
+
+ if (this.hover) {
+ this.buttonRenderer.drawButtonWhenMouseHover(event.gc, this);
+ return;
+ }
+
+ final boolean isToggleButton = (getStyle() & SWT.TOGGLE) == SWT.TOGGLE;
+ if (isToggleButton && this.selected) {
+ this.buttonRenderer.drawButtonWhenSelected(event.gc, this);
+ return;
+ }
+
+ this.buttonRenderer.drawButton(event.gc, this);
+ }
+
+ /**
+ * 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();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ this.selectionListeners.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) {
+ checkWidget();
+ final Point computedSize = this.buttonRenderer.computeSize(this, wHint, hHint, changed);
+
+ if (wHint != SWT.DEFAULT) {
+ computedSize.x = wHint;
+ }
+ if (hHint != SWT.DEFAULT) {
+ computedSize.y = hHint;
+ }
+ setWidth(computedSize.x);
+ setHeight(computedSize.y);
+ return computedSize;
+ }
+
+ /**
+ * Returns a value which describes the position of the text or image in the receiver. The value will be one of <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code> unless the receiver is an <code>ARROW</code> button, in which case, the
+ * alignment will indicate the direction of the arrow (one of <code>LEFT</code>, <code>RIGHT</code>, <code>UP</code> or <code>DOWN</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;
+ }
+
+ /**
+ * Gets the button renderer.
+ *
+ * @return the associated button renderer
+ */
+ public ButtonRenderer getButtonRenderer() {
+ checkWidget();
+ return this.buttonRenderer;
+ }
+
+ /**
+ * Returns the whole height of the widget.
+ *
+ * @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 this.computeSize(SWT.DEFAULT, SWT.DEFAULT, false).y;
+ }
+ return this.height;
+ }
+
+ /**
+ * 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 <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.selected;
+ }
+
+ /**
+ * Returns the receiver's text, which will be an empty string if it has never been set or if the receiver is an <code>ARROW</code> button.
+ *
+ * @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;
+ }
+
+ /**
+ * Returns the whole width of the widget.
+ *
+ * @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 computeSize(SWT.DEFAULT, SWT.DEFAULT, false).x;
+ }
+ return this.width;
+ }
+
+ /**
+ * 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, 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> unless the receiver is an <code>ARROW</code> button, in which case, the argument
+ * indicates the direction of the arrow (one of <code>LEFT</code>, <code>RIGHT</code>, <code>UP</code> or <code>DOWN</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 && alignment != SWT.RIGHT && alignment != SWT.CENTER) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.alignment = alignment;
+ redraw();
+ update();
+ }
+
+ /**
+ * Sets the button renderer.
+ *
+ * @param buttonRenderer the button renderer to set
+ */
+ public void setButtonRenderer(final ButtonRenderer buttonRenderer) {
+ this.buttonRenderer = buttonRenderer;
+ }
+
+ /**
+ * 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);
+ redraw();
+ update();
+ }
+
+ /**
+ * Sets the receiver's image to the argument, which may be <code>null</code> indicating that no image should be displayed.
+ *
+ * @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();
+ if (image != null && image.isDisposed()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.image = image;
+ this.buttonRenderer.createDisabledImage();
+ redraw();
+ update();
+ }
+
+ /**
+ * Sets the selection state of the receiver, if it is of type <code>TOGGLE</code>.
+ *
+ * @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.selected = selected;
+ redraw();
+ update();
+ }
+
+ /**
+ * Sets the receiver's text.
+ *
+ * @param string 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 string) {
+ checkWidget();
+ this.text = string;
+ redraw();
+ update();
+ }
+
+ /**
+ * 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);
+ redraw();
+ update();
+ }
+
+ /**
+ * 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();
+ update();
+ }
+
+ /**
+ * Sets the size.
+ *
+ * @param width the width
+ * @param height the height
+ * @see org.eclipse.swt.widgets.Control#setSize(int, int)
+ */
+ @Override
+ public void setSize(final int width, final int height) {
+ super.setSize(width, height);
+ redraw();
+ update();
+ }
+
+ /**
+ * Sets the size.
+ *
+ * @param size the new size
+ * @see org.eclipse.swt.widgets.Control#setSize(org.eclipse.swt.graphics.Point)
+ */
+ @Override
+ public void setSize(final Point size) {
+ super.setSize(size);
+ redraw();
+ update();
+ }
+
+ /**
+ * Sets the visible.
+ *
+ * @param visible the new visible
+ * @see org.eclipse.swt.widgets.Control#setVisible(boolean)
+ */
+ @Override
+ public void setVisible(final boolean visible) {
+ super.setVisible(visible);
+ redraw();
+ update();
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/OrangeButtonRenderer.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/OrangeButtonRenderer.java
new file mode 100644
index 0000000..732d80e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/OrangeButtonRenderer.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * 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.obutton;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This is the orange theme button renderer.
+ */
+public class OrangeButtonRenderer extends AbstractButtonRenderer {
+
+ /** The instance. */
+ private static OrangeButtonRenderer instance;
+
+ /** The Constant FIRST_BACKGROUND_COLOR. */
+ private static final Color FIRST_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(255, 195, 117);
+
+ /** The Constant SECOND_BACKGROUND_COLOR. */
+ private static final Color SECOND_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(238, 180, 79);
+
+ /**
+ * Instantiates a new orange button renderer.
+ */
+ private OrangeButtonRenderer() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getFontColor()
+ */
+ @Override
+ protected Color getFontColor() {
+ return Display.getDefault().getSystemColor(SWT.COLOR_WHITE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getFirstBackgroundColor()
+ */
+ @Override
+ protected Color getFirstBackgroundColor() {
+ return FIRST_BACKGROUND_COLOR;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getSecondBackgroundColor()
+ */
+ @Override
+ protected Color getSecondBackgroundColor() {
+ return SECOND_BACKGROUND_COLOR;
+ }
+
+ /**
+ * Gets the single instance of OrangeButtonRenderer.
+ *
+ * @return single instance of OrangeButtonRenderer
+ */
+ public static OrangeButtonRenderer getInstance() {
+ if (instance == null) {
+ instance = new OrangeButtonRenderer();
+ }
+ return instance;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/PurpleButtonRenderer.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/PurpleButtonRenderer.java
new file mode 100644
index 0000000..ed5c4c2
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/PurpleButtonRenderer.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * 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.obutton;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This is the purple theme button renderer.
+ */
+public class PurpleButtonRenderer extends AbstractButtonRenderer {
+
+ /** The instance. */
+ private static PurpleButtonRenderer instance;
+
+ /** The Constant FIRST_BACKGROUND_COLOR. */
+ private static final Color FIRST_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(192, 35, 221);
+
+ /** The Constant SECOND_BACKGROUND_COLOR. */
+ private static final Color SECOND_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(165, 17, 192);
+
+ /**
+ * Instantiates a new purple button renderer.
+ */
+ private PurpleButtonRenderer() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getFontColor()
+ */
+ @Override
+ protected Color getFontColor() {
+ return Display.getDefault().getSystemColor(SWT.COLOR_WHITE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getFirstBackgroundColor()
+ */
+ @Override
+ protected Color getFirstBackgroundColor() {
+ return FIRST_BACKGROUND_COLOR;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getSecondBackgroundColor()
+ */
+ @Override
+ protected Color getSecondBackgroundColor() {
+ return SECOND_BACKGROUND_COLOR;
+ }
+
+ /**
+ * Gets the single instance of PurpleButtonRenderer.
+ *
+ * @return single instance of PurpleButtonRenderer
+ */
+ public static PurpleButtonRenderer getInstance() {
+ if (instance == null) {
+ instance = new PurpleButtonRenderer();
+ }
+ return instance;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/RedButtonRenderer.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/RedButtonRenderer.java
new file mode 100644
index 0000000..b31a54f
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/obutton/RedButtonRenderer.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * 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.obutton;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This is the red theme button renderer.
+ */
+public class RedButtonRenderer extends AbstractButtonRenderer {
+
+ /** The instance. */
+ private static RedButtonRenderer instance;
+
+ /** The Constant FIRST_BACKGROUND_COLOR. */
+ private static final Color FIRST_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(254, 26, 0);
+
+ /** The Constant SECOND_BACKGROUND_COLOR. */
+ private static final Color SECOND_BACKGROUND_COLOR = SWTGraphicUtil.getColorSafely(208, 2, 0);
+
+ /**
+ * Instantiates a new red button renderer.
+ */
+ private RedButtonRenderer() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getFontColor()
+ */
+ @Override
+ protected Color getFontColor() {
+ return Display.getDefault().getSystemColor(SWT.COLOR_WHITE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getFirstBackgroundColor()
+ */
+ @Override
+ protected Color getFirstBackgroundColor() {
+ return FIRST_BACKGROUND_COLOR;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.obutton.AbstractButtonRenderer#getSecondBackgroundColor()
+ */
+ @Override
+ protected Color getSecondBackgroundColor() {
+ return SECOND_BACKGROUND_COLOR;
+ }
+
+ /**
+ * Gets the single instance of RedButtonRenderer.
+ *
+ * @return single instance of RedButtonRenderer
+ */
+ public static RedButtonRenderer getInstance() {
+ if (instance == null) {
+ instance = new RedButtonRenderer();
+ }
+ return instance;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/ChoiceItem.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/ChoiceItem.java
new file mode 100644
index 0000000..1f991e5
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/ChoiceItem.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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.opalDialog;
+
+/**
+ * Instances of this class are choice items used by the choice widget.
+ */
+public class ChoiceItem {
+
+ /** The instruction. */
+ private final String instruction;
+
+ /** The text. */
+ private final String text;
+
+ /**
+ * Constructor.
+ *
+ * @param instruction instruction of the choice
+ * @param text text displayed under the instruction
+ */
+ public ChoiceItem(final String instruction, final String text) {
+ this.instruction = instruction;
+ this.text = text;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param instruction instruction
+ */
+ public ChoiceItem(final String instruction) {
+ this(instruction, null);
+ }
+
+ /**
+ * Gets the instruction.
+ *
+ * @return the instruction
+ */
+ public String getInstruction() {
+ return this.instruction;
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @return the text
+ */
+ public String getText() {
+ return this.text;
+ };
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/ChoiceWidget.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/ChoiceWidget.java
new file mode 100644
index 0000000..3f4d286
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/ChoiceWidget.java
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ * 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.opalDialog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+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.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+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.Widget;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instance of this class are composite that represents a choice like in Windows
+ * Vista and Seven. It is composed of a green arrow, instruction and text
+ */
+public class ChoiceWidget extends Composite {
+
+ /** The old image. */
+ private Image oldImage;
+
+ /** The choice item. */
+ private ChoiceItem choiceItem;
+
+ /** The image. */
+ private Label image;
+
+ /** The instruction. */
+ private Label instruction;
+
+ /** The text. */
+ private Label text;
+
+ /** The selection listeners. */
+ private final List<SelectionListener> selectionListeners;
+
+ /** The selection. */
+ private boolean selection;
+
+ /** The inside composite. */
+ private boolean insideComposite;
+
+ /** The inside image. */
+ private boolean insideImage;
+
+ /** The inside text. */
+ private boolean insideText;
+
+ /** The inside instruction. */
+ private boolean insideInstruction;
+
+ /**
+ * 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 ChoiceWidget(final Composite parent, final int style) {
+ super(parent, style);
+
+ this.setBackgroundMode(SWT.INHERIT_DEFAULT);
+ this.setLayout(new GridLayout(2, false));
+
+ buildGreenArrow();
+ buildInstruction();
+ buildText();
+ addMouseListeners();
+
+ this.selectionListeners = new ArrayList<SelectionListener>();
+ this.addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ drawComposite();
+ }
+ });
+
+ }
+
+ /**
+ * Build the green arrow.
+ */
+ private void buildGreenArrow() {
+ final Image greenArrow = SWTGraphicUtil.createImageFromFile("images/arrowGreenRight.png");
+ this.image = new Label(this, SWT.NONE);
+ this.image.setImage(greenArrow);
+ this.image.setLayoutData(new GridData(GridData.CENTER, GridData.BEGINNING, false, false, 1, 2));
+ SWTGraphicUtil.addDisposer(this, greenArrow);
+ }
+
+ /**
+ * Build the instruction.
+ */
+ private void buildInstruction() {
+ final Color color = new Color(Display.getCurrent(), 35, 107, 178);
+ SWTGraphicUtil.addDisposer(this, color);
+
+ this.instruction = new Label(this, SWT.NONE);
+ this.instruction.setForeground(color);
+ this.instruction.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false));
+ }
+
+ /**
+ * Build the panel.
+ */
+ private void buildText() {
+ this.text = new Label(this, SWT.NONE);
+ this.text.setForeground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ this.text.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, true));
+ }
+
+ /**
+ * Add mouse listeners.
+ */
+ private void addMouseListeners() {
+ final Listener mouseEnterListener = new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+
+ if (event.widget.equals(ChoiceWidget.this)) {
+ ChoiceWidget.this.insideComposite = true;
+ }
+
+ if (event.widget.equals(ChoiceWidget.this.image)) {
+ ChoiceWidget.this.insideImage = true;
+ }
+ if (event.widget.equals(ChoiceWidget.this.text)) {
+ ChoiceWidget.this.insideText = true;
+ }
+ if (event.widget.equals(ChoiceWidget.this.instruction)) {
+ ChoiceWidget.this.insideInstruction = true;
+ }
+
+ drawComposite();
+ }
+ };
+
+ final Listener mouseExitListener = new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ if (event.widget.equals(ChoiceWidget.this)) {
+ ChoiceWidget.this.insideComposite = false;
+ }
+
+ if (event.widget.equals(ChoiceWidget.this.image)) {
+ ChoiceWidget.this.insideImage = false;
+ }
+ if (event.widget.equals(ChoiceWidget.this.text)) {
+ ChoiceWidget.this.insideText = false;
+ }
+ if (event.widget.equals(ChoiceWidget.this.instruction)) {
+ ChoiceWidget.this.insideInstruction = false;
+ }
+ drawComposite();
+ }
+ };
+
+ final Listener mouseClickListener = new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ for (final SelectionListener selectionListener : ChoiceWidget.this.selectionListeners) {
+ selectionListener.widgetSelected(null);
+ }
+ }
+ };
+
+ addListener(SWT.MouseEnter, mouseEnterListener);
+ this.image.addListener(SWT.MouseEnter, mouseEnterListener);
+ this.text.addListener(SWT.MouseEnter, mouseEnterListener);
+ this.instruction.addListener(SWT.MouseEnter, mouseEnterListener);
+
+ addListener(SWT.MouseExit, mouseExitListener);
+ this.image.addListener(SWT.MouseExit, mouseExitListener);
+ this.text.addListener(SWT.MouseExit, mouseExitListener);
+ this.instruction.addListener(SWT.MouseExit, mouseExitListener);
+
+ addListener(SWT.MouseUp, mouseClickListener);
+ this.image.addListener(SWT.MouseUp, mouseClickListener);
+ this.text.addListener(SWT.MouseUp, mouseClickListener);
+ this.instruction.addListener(SWT.MouseUp, mouseClickListener);
+ }
+
+ /**
+ * Draw the composite.
+ */
+ private void drawComposite() {
+
+ final Rectangle rect = this.getClientArea();
+ final Image newImage = new Image(getDisplay(), Math.max(1, rect.width), Math.max(1, rect.height));
+
+ final GC gc = new GC(newImage);
+
+ final boolean inside = this.insideComposite || this.insideImage || this.insideInstruction || this.insideText;
+
+ if (!inside && !this.selection) {
+ gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ gc.drawRectangle(rect.x, rect.y, rect.width, rect.height);
+ } else {
+ // The mouse is over OR the item is selected
+ final Color gradientColor = inside ? new Color(getDisplay(), 220, 231, 243) : new Color(getDisplay(), 241, 241, 241);
+ final Color borderColor = inside ? new Color(getDisplay(), 35, 107, 178) : new Color(getDisplay(), 192, 192, 192);
+
+ gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ gc.setBackground(gradientColor);
+ gc.fillGradientRectangle(rect.x, rect.y, rect.width, rect.height, true);
+
+ gc.setForeground(borderColor);
+ gc.drawRoundRectangle(rect.x, rect.y, rect.width - 1, rect.height - 1, 2, 2);
+
+ gradientColor.dispose();
+ borderColor.dispose();
+ }
+ gc.dispose();
+
+ this.setBackgroundImage(newImage);
+ if (this.oldImage != null) {
+ this.oldImage.dispose();
+ }
+ this.oldImage = newImage;
+
+ }
+
+ /**
+ * Gets the choice item.
+ *
+ * @return the current choice item
+ */
+ public ChoiceItem getChoiceItem() {
+ return this.choiceItem;
+ }
+
+ /**
+ * Sets the choice item.
+ *
+ * @param choiceItem the choiceItem to set
+ */
+ public void setChoiceItem(final ChoiceItem choiceItem) {
+ this.choiceItem = choiceItem;
+ this.instruction.setText(choiceItem.getInstruction());
+ this.text.setText(choiceItem.getText());
+ }
+
+ /**
+ * Add a selection listener to this widget.
+ *
+ * @param listener listener to add
+ */
+ public void addSelectionListener(final SelectionListener listener) {
+ this.selectionListeners.add(listener);
+ }
+
+ /**
+ * Remove a selection listener.
+ *
+ * @param listener listener to remove
+ */
+ public void removeSelectionListener(final SelectionListener listener) {
+ this.selectionListeners.remove(listener);
+ }
+
+ /**
+ * Sets the selection.
+ *
+ * @param selection the new selection
+ */
+ public void setSelection(final boolean selection) {
+ this.selection = selection;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/Dialog.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/Dialog.java
new file mode 100644
index 0000000..aa37c59
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/Dialog.java
@@ -0,0 +1,592 @@
+/*******************************************************************************
+ * 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.opalDialog;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are dialog box
+ * This component was inspired by the Oxbow Project (http://code.google.com/p/oxbow/) by Eugene Ryzhikov
+ */
+public class Dialog {
+
+ /**
+ * Types of opal dialog.
+ */
+ public enum OpalDialogType {
+
+ /** The close. */
+ CLOSE,
+ /** The yes no. */
+ YES_NO,
+ /** The ok. */
+ OK,
+ /** The ok cancel. */
+ OK_CANCEL,
+ /** The select cancel. */
+ SELECT_CANCEL,
+ /** The no button. */
+ NO_BUTTON,
+ /** The other. */
+ OTHER,
+ /** The none. */
+ NONE
+ }
+
+ /**
+ * The Enum CenterOption.
+ */
+ public enum CenterOption {
+
+ /** The center on screen. */
+ CENTER_ON_SCREEN,
+ /** The center on dialog. */
+ CENTER_ON_DIALOG
+ }
+
+ /** The center policy. */
+ private CenterOption centerPolicy = CenterOption.CENTER_ON_SCREEN;
+
+ /** The title. */
+ private String title;
+
+ /** The button type. */
+ OpalDialogType buttonType;
+
+ /** The message area. */
+ private final MessageArea messageArea;
+
+ /** The footer area. */
+ private final FooterArea footerArea;
+
+ /** The shell. */
+ final Shell shell;
+
+ /** The minimum width. */
+ private int minimumWidth = 300;
+
+ /** The minimum height. */
+ private int minimumHeight = 150;
+
+ /**
+ * Constructor.
+ */
+ public Dialog() {
+ this(null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param resizable if <code>true</code>, the window is resizable
+ */
+ public Dialog(final boolean resizable) {
+ this(null, resizable);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param parent parent shell
+ */
+ public Dialog(final Shell parent) {
+ this(parent, false);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param parent parent shell
+ * @param resizable if <code>true</code>, the window is resizable
+ */
+ public Dialog(final Shell parent, final boolean resizable) {
+ if (parent == null) {
+ this.shell = new Shell(Display.getCurrent(), SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | (resizable ? SWT.RESIZE : SWT.NONE));
+ } else {
+ this.shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | (resizable ? SWT.RESIZE : SWT.NONE));
+ if (parent.getImage() != null) {
+ this.shell.setImage(parent.getImage());
+ }
+ }
+ this.messageArea = new MessageArea(this);
+ this.footerArea = new FooterArea(this);
+ }
+
+ /**
+ * Show the dialog box.
+ *
+ * @return the index of the selected button
+ */
+ public int show() {
+ final GridLayout gd = new GridLayout(1, true);
+ gd.horizontalSpacing = 0;
+ gd.verticalSpacing = 0;
+ gd.marginHeight = gd.marginWidth = 0;
+ this.shell.setLayout(gd);
+
+ this.messageArea.render();
+ this.footerArea.render();
+ if (this.title != null) {
+ this.shell.setText(this.title);
+ }
+ pack();
+ this.shell.open();
+
+ final Display display = this.shell.getDisplay();
+ while (!this.shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ return this.footerArea.getSelectedButton();
+ }
+
+ /**
+ * Close the dialog box.
+ */
+ public void close() {
+ this.shell.dispose();
+
+ }
+
+ /**
+ * Compute the size of the shell.
+ */
+ void pack() {
+
+ final Point preferredSize = this.shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+
+ if (preferredSize.x < this.minimumWidth) {
+ preferredSize.x = this.minimumWidth;
+ }
+
+ if (preferredSize.y < this.minimumHeight) {
+ preferredSize.y = this.minimumHeight;
+ }
+
+ final int centerX;
+ final int centerY;
+
+ if (this.centerPolicy == CenterOption.CENTER_ON_SCREEN || this.shell.getParent() == null) {
+ final Rectangle monitorBounds = SWTGraphicUtil.getBoundsOfMonitorOnWhichShellIsDisplayed(this.shell);
+ centerX = monitorBounds.x + (monitorBounds.width - preferredSize.x) / 2;
+ centerY = monitorBounds.y + (monitorBounds.height - preferredSize.y) / 2;
+ } else {
+ final Shell parent = (Shell) this.shell.getParent();
+ centerX = parent.getLocation().x + (parent.getSize().x - preferredSize.x) / 2;
+ centerY = parent.getLocation().y + (parent.getSize().y - preferredSize.y) / 2;
+ }
+
+ this.shell.setBounds(centerX, centerY, preferredSize.x, preferredSize.y);
+ }
+
+ // ------------------------------------------- Convenient methods
+
+ /**
+ * Create a dialog box that asks a question.
+ *
+ * @param title title of the dialog box
+ * @param text text of the question
+ * @param defaultValue default value of the input
+ * @return the value typed by the user
+ */
+ public static String ask(final String title, final String text, final String defaultValue) {
+ return ask(null, title, text, defaultValue);
+ }
+
+ /**
+ * Create a dialog box that asks a question.
+ *
+ * @param shell the shell
+ * @param title title of the dialog box
+ * @param text text of the question
+ * @param defaultValue default value of the input
+ * @return the value typed by the user
+ * @shell parent shell
+ */
+ public static String ask(final Shell shell, final String title, final String text, final String defaultValue) {
+ final Dialog dialog = new Dialog(shell);
+ dialog.setTitle(ResourceManager.getLabel(ResourceManager.INPUT));
+ dialog.getMessageArea().setTitle(title).setText(text).setIcon(Display.getCurrent().getSystemImage(SWT.ICON_QUESTION)).addTextBox(defaultValue);
+ dialog.setButtonType(OpalDialogType.OK_CANCEL);
+ if (dialog.show() == 0) {
+ return dialog.getMessageArea().getTextBoxValue();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Create a dialog box that displays an error message.
+ *
+ * @param title title of the dialog box
+ * @param errorMessage Error message
+ */
+ public static void error(final String title, final String errorMessage) {
+ error(null, title, errorMessage);
+ }
+
+ /**
+ * Create a dialog box that displays an error message.
+ *
+ * @param shell parent shell
+ * @param title title of the dialog box
+ * @param errorMessage Error message
+ */
+ public static void error(final Shell shell, final String title, final String errorMessage) {
+ final Dialog dialog = new Dialog(shell);
+ dialog.setTitle(ResourceManager.getLabel(ResourceManager.APPLICATION_ERROR));
+ dialog.getMessageArea().setTitle(title).//
+ setText(errorMessage).//
+ setIcon(Display.getCurrent().getSystemImage(SWT.ICON_ERROR));
+ dialog.setButtonType(OpalDialogType.OK);
+ dialog.show();
+ }
+
+ /**
+ * Create a dialog box that inform the user.
+ *
+ * @param title title of the dialog box
+ * @param text text to display
+ */
+ public static void inform(final String title, final String text) {
+ inform(null, title, text);
+ }
+
+ /**
+ * Create a dialog box that inform the user.
+ *
+ * @param shell parent shell
+ * @param title title of the dialog box
+ * @param text text to display
+ */
+ public static void inform(final Shell shell, final String title, final String text) {
+ final Dialog dialog = new Dialog(shell);
+ dialog.setTitle(ResourceManager.getLabel(ResourceManager.INFORMATION));
+ dialog.getMessageArea().setTitle(title).setText(text).setIcon(Display.getCurrent().getSystemImage(SWT.ICON_INFORMATION));
+ dialog.setButtonType(OpalDialogType.CLOSE);
+ dialog.show();
+ }
+
+ /**
+ * Create a dialog box that asks the user a confirmation.
+ *
+ * @param title title of the dialog box
+ * @param text text to display
+ * @return <code>true</code> if the user confirmed, <code>false</code>
+ * otherwise
+ */
+ public static boolean isConfirmed(final String title, final String text) {
+ return isConfirmed(null, title, text, -1);
+ }
+
+ /**
+ * Create a dialog box that asks the user a confirmation.
+ *
+ * @param shell parent shell
+ * @param title title of the dialog box
+ * @param text text to display
+ * @return <code>true</code> if the user confirmed, <code>false</code>
+ * otherwise
+ */
+ public static boolean isConfirmed(final Shell shell, final String title, final String text) {
+ return isConfirmed(shell, title, text, -1);
+ }
+
+ /**
+ * Create a dialog box that asks the user a confirmation. The button "yes" is not enabled before timer seconds
+ *
+ * @param title title of the dialog box
+ * @param text text to display
+ * @param timer number of seconds before enabling the yes button
+ * @return <code>true</code> if the user confirmed, <code>false</code> otherwise
+ */
+ public static boolean isConfirmed(final String title, final String text, final int timer) {
+ return isConfirmed(null, title, text, timer);
+ }
+
+ /**
+ * Create a dialog box that asks the user a confirmation. The button "yes" is not enabled before timer seconds
+ *
+ * @param shell parent shell
+ * @param title title of the dialog box
+ * @param text text to display
+ * @param timer number of seconds before enabling the yes button
+ * @return <code>true</code> if the user confirmed, <code>false</code> otherwise
+ */
+ public static boolean isConfirmed(final Shell shell, final String title, final String text, final int timer) {
+ final Dialog dialog = new Dialog(shell);
+ dialog.setTitle(ResourceManager.getLabel(ResourceManager.WARNING));
+ dialog.getMessageArea().setTitle(title).setText(text).setIcon(Display.getCurrent().getSystemImage(SWT.ICON_WARNING));
+
+ dialog.getFooterArea().setTimer(timer).setTimerIndexButton(0);
+ dialog.setButtonType(OpalDialogType.YES_NO);
+ return dialog.show() == 0;
+ }
+
+ /**
+ * Create a dialog box with a radio choice.
+ *
+ * @param title title of the dialog box
+ * @param text text to display
+ * @param defaultSelection index of the default selection
+ * @param values values to display
+ * @return the index of the selection
+ */
+ public static int radioChoice(final String title, final String text, final int defaultSelection, final String... values) {
+ return radioChoice(null, title, text, defaultSelection, values);
+ }
+
+ /**
+ * Create a dialog box with a radio choice.
+ *
+ * @param shell parent shell
+ * @param title title of the dialog box
+ * @param text text to display
+ * @param defaultSelection index of the default selection
+ * @param values values to display
+ * @return the index of the selection
+ */
+ public static int radioChoice(final Shell shell, final String title, final String text, final int defaultSelection, final String... values) {
+ final Dialog dialog = new Dialog(shell);
+ dialog.setTitle(ResourceManager.getLabel(ResourceManager.CHOICE));
+ dialog.getMessageArea().setTitle(title).setText(text).setIcon(Display.getCurrent().getSystemImage(SWT.ICON_QUESTION)).addRadioButtons(defaultSelection, values);
+ dialog.setButtonType(OpalDialogType.SELECT_CANCEL);
+ if (dialog.show() == 0) {
+ return dialog.getMessageArea().getRadioChoice();
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Display a dialog box with an exception.
+ *
+ * @param exception exception to display
+ */
+ public static void showException(final Throwable exception) {
+ final Dialog dialog = new Dialog();
+ dialog.setTitle(ResourceManager.getLabel(ResourceManager.EXCEPTION));
+
+ final String msg = exception.getMessage();
+ final String className = exception.getClass().getName();
+ final boolean noMessage = msg == null || msg.trim().length() == 0;
+
+ dialog.getMessageArea().setTitle(noMessage ? className : msg).//
+ setText(noMessage ? "" : className).//
+ setIcon(Display.getCurrent().getSystemImage(SWT.ICON_ERROR)).//
+ setException(exception);
+
+ dialog.getFooterArea().setExpanded(true);
+
+ dialog.setButtonType(OpalDialogType.CLOSE);
+ dialog.show();
+ }
+
+ /**
+ * Create a dialog box with a choice.
+ *
+ * @param title title of the dialog box
+ * @param text text to display
+ * @param defaultSelection index of the default selection
+ * @param items items to display
+ * @return the index of the selected value
+ */
+ public static int choice(final String title, final String text, final int defaultSelection, final ChoiceItem... items) {
+ return choice(null, title, text, defaultSelection, items);
+ }
+
+ /**
+ * Create a dialog box with a choice.
+ *
+ * @param shell parent shell
+ * @param title title of the dialog box
+ * @param text text to display
+ * @param defaultSelection index of the default selection
+ * @param items items to display
+ * @return the index of the selected value
+ */
+ public static int choice(final Shell shell, final String title, final String text, final int defaultSelection, final ChoiceItem... items) {
+ final Dialog dialog = new Dialog(shell);
+ dialog.setTitle(ResourceManager.getLabel(ResourceManager.CHOICE));
+ dialog.getMessageArea().setTitle(title).setText(text).setIcon(Display.getCurrent().getSystemImage(SWT.ICON_QUESTION)).addChoice(defaultSelection, items);
+ dialog.setButtonType(OpalDialogType.NONE);
+ dialog.show();
+ return dialog.getMessageArea().getChoice();
+ }
+
+ // ------------------------------------------- Getters & Setters
+
+ /**
+ * Gets the title.
+ *
+ * @return the title
+ */
+ public String getTitle() {
+ return this.title;
+ }
+
+ /**
+ * Sets the title.
+ *
+ * @param title the title to set
+ */
+ public void setTitle(final String title) {
+ this.title = title;
+ }
+
+ /**
+ * Gets the button type.
+ *
+ * @return the buttonType
+ */
+ public OpalDialogType getButtonType() {
+ return this.buttonType;
+ }
+
+ /**
+ * Sets the button type.
+ *
+ * @param buttonType the buttonType to set
+ */
+ public void setButtonType(final OpalDialogType buttonType) {
+ this.buttonType = buttonType;
+
+ switch (buttonType) {
+ case CLOSE:
+ this.footerArea.setButtonLabels(ResourceManager.getLabel(ResourceManager.CLOSE)).setDefaultButtonIndex(0);
+ break;
+ case NO_BUTTON:
+ break;
+ case OK:
+ this.footerArea.setButtonLabels(ResourceManager.getLabel(ResourceManager.OK)).setDefaultButtonIndex(0);
+ break;
+ case OK_CANCEL:
+ this.footerArea.setButtonLabels(ResourceManager.getLabel(ResourceManager.OK), ResourceManager.getLabel(ResourceManager.CANCEL)).setDefaultButtonIndex(-1);
+ break;
+ case SELECT_CANCEL:
+ this.footerArea.setButtonLabels(ResourceManager.getLabel(ResourceManager.SELECT), ResourceManager.getLabel(ResourceManager.CANCEL)).setDefaultButtonIndex(-1);
+ break;
+ case YES_NO:
+ this.footerArea.setButtonLabels(ResourceManager.getLabel(ResourceManager.YES), ResourceManager.getLabel(ResourceManager.NO)).setDefaultButtonIndex(0);
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ /**
+ * Gets the message area.
+ *
+ * @return the messageArea
+ */
+ public MessageArea getMessageArea() {
+ return this.messageArea;
+ }
+
+ /**
+ * Gets the footer area.
+ *
+ * @return the footerArea
+ */
+ public FooterArea getFooterArea() {
+ return this.footerArea;
+ }
+
+ /**
+ * Gets the shell.
+ *
+ * @return the shell
+ */
+ public Shell getShell() {
+ return this.shell;
+ }
+
+ /**
+ * Gets the selected button.
+ *
+ * @return the index of the selected button
+ */
+ public int getSelectedButton() {
+ return getFooterArea().getSelectedButton();
+ }
+
+ /**
+ * Gets the checkbox value.
+ *
+ * @return the selection state of the checkbox
+ */
+ public boolean getCheckboxValue() {
+ return this.footerArea.getCheckBoxValue();
+ }
+
+ /**
+ * Gets the minimum width.
+ *
+ * @return the minimum width of the dialog box
+ */
+ public int getMinimumWidth() {
+ return this.minimumWidth;
+ }
+
+ /**
+ * Sets the minimum width.
+ *
+ * @param minimumWidth the minimum width of the dialog box to set
+ */
+ public void setMinimumWidth(final int minimumWidth) {
+ this.minimumWidth = minimumWidth;
+ }
+
+ /**
+ * Gets the minimum height.
+ *
+ * @return the minimum height of the dialog box
+ */
+ public int getMinimumHeight() {
+ return this.minimumHeight;
+ }
+
+ /**
+ * Sets the minimum height.
+ *
+ * @param minimumHeight the minimum height of the dialog box to set
+ */
+ public void setMinimumHeight(final int minimumHeight) {
+ this.minimumHeight = minimumHeight;
+ }
+
+ /**
+ * Gets the center policy.
+ *
+ * @return the center policy (Dialog centered on screen or centered in the
+ * center of the parent window)
+ */
+ public CenterOption getCenterPolicy() {
+ return this.centerPolicy;
+ }
+
+ /**
+ * Sets the center policy.
+ *
+ * @param centerPolicy center policy
+ */
+ public void setCenterPolicy(final CenterOption centerPolicy) {
+ this.centerPolicy = centerPolicy;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/DialogArea.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/DialogArea.java
new file mode 100644
index 0000000..9a92355
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/DialogArea.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * 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.opalDialog;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This abstract class if the mother of MessageArea and FooterArea classes.
+ */
+abstract class DialogArea {
+
+ /** The Constant MORE_DETAILS_IMAGE. */
+ private static final String MORE_DETAILS_IMAGE = "moreDetails.png";
+
+ /** The Constant FEWER_DETAILS_IMAGE. */
+ private static final String FEWER_DETAILS_IMAGE = "fewerDetails.png";
+
+ /** The Constant WINDOWS_DEFAULT_FONT. */
+ private static final String WINDOWS_DEFAULT_FONT = "Segoe UI";
+
+ /** The Constant MAC_OS_DEFAULT_FONT. */
+ private static final String MAC_OS_DEFAULT_FONT = "Lucida Grande";
+
+ /** The parent. */
+ protected final Dialog parent;
+
+ /** The initialised. */
+ private boolean initialised;
+
+ /**
+ * Constructor.
+ *
+ * @param parent parent dialog
+ */
+ public DialogArea(final Dialog parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Render the content of an area.
+ */
+ abstract void render();
+
+ /**
+ * Checks if is initialised.
+ *
+ * @return the initialised field
+ */
+ boolean isInitialised() {
+ return this.initialised;
+ }
+
+ /**
+ * Sets the initialised.
+ *
+ * @param initialised the initialised value to set
+ */
+ void setInitialised(final boolean initialised) {
+ this.initialised = initialised;
+ }
+
+ /**
+ * Gets the normal font.
+ *
+ * @return the normal font used by the dialog box
+ */
+ protected Font getNormalFont() {
+ if (SWTGraphicUtil.isMacOS()) {
+ return getFont(MAC_OS_DEFAULT_FONT, 11, SWT.NONE);
+ } else {
+ return getFont(WINDOWS_DEFAULT_FONT, 9, SWT.NONE);
+ }
+ }
+
+ /**
+ * Gets the bigger font.
+ *
+ * @return the bigger font used by the dialog box
+ */
+ protected Font getBiggerFont() {
+ if (SWTGraphicUtil.isMacOS()) {
+ return getFont(MAC_OS_DEFAULT_FONT, 13, SWT.NONE);
+ } else {
+ return getFont(WINDOWS_DEFAULT_FONT, 11, SWT.NONE);
+ }
+ }
+
+ /**
+ * Build a font.
+ *
+ * @param name name of the font
+ * @param size size of the font
+ * @param style style of the font
+ * @return the font
+ */
+ private Font getFont(final String name, final int size, final int style) {
+ final Font font = new Font(Display.getCurrent(), name, size, style);
+ this.parent.shell.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ SWTGraphicUtil.safeDispose(font);
+ }
+ });
+ return font;
+ }
+
+ /**
+ * Gets the title color.
+ *
+ * @return the title's color (blue)
+ */
+ protected Color getTitleColor() {
+ final Color color = new Color(Display.getCurrent(), 35, 107, 178);
+ SWTGraphicUtil.addDisposer(this.parent.shell, color);
+ return color;
+ }
+
+ /**
+ * Gets the grey color.
+ *
+ * @return the grey color
+ */
+ protected Color getGreyColor() {
+ final Color color = new Color(Display.getCurrent(), 240, 240, 240);
+ SWTGraphicUtil.addDisposer(this.parent.shell, color);
+ return color;
+ }
+
+ /**
+ * Gets the fewer details image.
+ *
+ * @return the image "fewer details"
+ */
+ protected Image getFewerDetailsImage() {
+ return loadImage("images/" + FEWER_DETAILS_IMAGE);
+ }
+
+ /**
+ * Gets the more details image.
+ *
+ * @return the image "more details"
+ */
+ protected Image getMoreDetailsImage() {
+ return loadImage("images/" + MORE_DETAILS_IMAGE);
+ }
+
+ /**
+ * Loads an image.
+ *
+ * @param fileName file name of the image
+ * @return the image
+ */
+ private Image loadImage(final String fileName) {
+ final Image image = SWTGraphicUtil.createImageFromFile(fileName);
+ SWTGraphicUtil.addDisposer(this.parent.shell, image);
+ return image;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/FooterArea.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/FooterArea.java
new file mode 100644
index 0000000..460b392
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/FooterArea.java
@@ -0,0 +1,611 @@
+/*******************************************************************************
+ * 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.opalDialog;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+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.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * Instances of this class are message areas.
+ */
+public class FooterArea extends DialogArea {
+
+ /** The Constant BUTTON_WIDTH. */
+ private static final int BUTTON_WIDTH = 70;
+
+ /** The icon. */
+ private Image icon;
+
+ /** The footer text. */
+ private String footerText;
+
+ /** The button labels. */
+ private List<String> buttonLabels;
+
+ /** The default button index. */
+ private int defaultButtonIndex;
+
+ /** The timer. */
+ private int timer;
+
+ /** The timer index button. */
+ private int timerIndexButton;
+
+ /** The selected button index. */
+ int selectedButtonIndex;
+
+ /** The collapsed label text. */
+ private String collapsedLabelText;
+
+ /** The expanded label text. */
+ private String expandedLabelText;
+
+ /** The expanded. */
+ private boolean expanded;
+
+ /** The detail text. */
+ private String detailText;
+
+ /** The details. */
+ private boolean details;
+
+ /** The disabled button. */
+ private Button disabledButton;
+
+ /** The check box label. */
+ private String checkBoxLabel;
+
+ /** The check box value. */
+ private boolean checkBoxValue;
+
+ /** The expanded panel. */
+ private Text expandedPanel;
+
+ /** The composite. */
+ private Composite composite;
+
+ /**
+ * Constructor.
+ *
+ * @param parent dialog that is composed of this footer area
+ */
+ public FooterArea(final Dialog parent) {
+ super(parent);
+ this.selectedButtonIndex = -1;
+ this.expandedLabelText = ResourceManager.getLabel(ResourceManager.FEWER_DETAILS);
+ this.collapsedLabelText = ResourceManager.getLabel(ResourceManager.MORE_DETAILS);
+ this.timer = -1;
+ this.timerIndexButton = -1;
+ }
+
+ /**
+ * Add a check box.
+ *
+ * @param label label to display
+ * @param selection default value of the check box
+ * @return this footer area
+ */
+ public FooterArea addCheckBox(final String label, final boolean selection) {
+ this.checkBoxLabel = label;
+ this.checkBoxValue = selection;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Render.
+ *
+ * @see org.mihalis.opal.OpalDialog.DialogArea#render()
+ */
+ @Override
+ void render() {
+ if (!this.isInitialised()) {
+ return;
+ }
+
+ this.createSeparator();
+
+ this.composite = new Composite(this.parent.shell, SWT.NONE);
+ this.composite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+ this.composite.setBackground(this.getGreyColor());
+
+ int numberOfColumns = this.buttonLabels == null ? 0 : this.buttonLabels.size();
+ if (this.details) {
+ numberOfColumns += 2;
+ }
+
+ final GridLayout gridLayout = new GridLayout(numberOfColumns, false);
+ gridLayout.marginHeight = gridLayout.marginWidth = 10;
+ this.composite.setLayout(gridLayout);
+
+ if (this.details) {
+ this.createDetails(numberOfColumns);
+ }
+
+ if (this.buttonLabels != null) {
+ this.createButtons();
+ }
+
+ if (this.details && this.parent.getMessageArea().getException() == null && this.expanded) {
+ this.createExpandedPanel(numberOfColumns);
+ }
+
+ if (this.checkBoxLabel != null) {
+ this.createCheckBox(numberOfColumns);
+ }
+
+ if (this.footerText != null) {
+ this.createFooter();
+
+ }
+
+ }
+
+ /**
+ * Create the buttons.
+ */
+ private void createButtons() {
+ Button defaultButton = null;
+ for (int i = 0; i < this.buttonLabels.size(); i++) {
+ final Button button = new Button(this.composite, SWT.PUSH);
+ button.setText(this.buttonLabels.get(i));
+
+ final GridData gd = new GridData(GridData.END, GridData.CENTER, i == 0, false);
+ final int defaultWidth = button.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
+ gd.minimumWidth = Math.max(BUTTON_WIDTH, defaultWidth);
+ gd.widthHint = Math.max(BUTTON_WIDTH, defaultWidth);
+ button.setLayoutData(gd);
+
+ if (i == this.defaultButtonIndex) {
+ defaultButton = button;
+ }
+
+ final Integer integer = Integer.valueOf(i);
+ button.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ FooterArea.this.parent.shell.dispose();
+ FooterArea.this.selectedButtonIndex = integer.intValue();
+ }
+
+ });
+
+ if (i == this.timerIndexButton && this.timer != -1) {
+ this.disabledButton = button;
+ button.setData(button.getText());
+ button.setText(button.getText() + " (" + this.timer + ")");
+ button.setEnabled(false);
+ }
+
+ }
+
+ if (this.timerIndexButton != -1 && this.timer != -1) {
+ Display.getCurrent().timerExec(1000, new Runnable() {
+
+ @Override
+ public void run() {
+ FooterArea.this.timer--;
+ if (FooterArea.this.disabledButton.isDisposed()) {
+ return;
+ }
+
+ if (FooterArea.this.timer == 0) {
+ FooterArea.this.disabledButton.setText((String) FooterArea.this.disabledButton.getData());
+ FooterArea.this.disabledButton.setEnabled(true);
+ } else {
+ FooterArea.this.disabledButton.setText(FooterArea.this.disabledButton.getData() + " (" + FooterArea.this.timer + ")");
+ Display.getCurrent().timerExec(1000, this);
+ }
+
+ }
+ });
+ }
+
+ this.parent.shell.setDefaultButton(defaultButton);
+ }
+
+ /**
+ * Create the details section.
+ *
+ * @param numberOfColumns the number of columns
+ */
+ private void createDetails(final int numberOfColumns) {
+ final Label icon = new Label(this.composite, SWT.NONE);
+ icon.setBackground(this.getGreyColor());
+ icon.setImage(this.isExpanded() ? this.getFewerDetailsImage() : this.getMoreDetailsImage());
+ icon.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
+
+ final Label label = new Label(this.composite, SWT.NONE);
+ label.setBackground(this.getGreyColor());
+ label.setText(this.isExpanded() ? this.expandedLabelText : this.collapsedLabelText);
+ label.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+
+ final int numberOfColumnsParam = numberOfColumns;
+
+ final Listener listener = new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ if (FooterArea.this.parent.getMessageArea().getException() != null) {
+ if (label.getText().equals(FooterArea.this.expandedLabelText)) {
+ label.setText(FooterArea.this.collapsedLabelText);
+ icon.setImage(FooterArea.this.getMoreDetailsImage());
+ FooterArea.this.parent.getMessageArea().hideException();
+ } else {
+ label.setText(FooterArea.this.expandedLabelText);
+ icon.setImage(FooterArea.this.getFewerDetailsImage());
+ FooterArea.this.parent.getMessageArea().showException();
+ }
+
+ } else {
+ if (label.getText().equals(FooterArea.this.expandedLabelText)) {
+ label.setText(FooterArea.this.collapsedLabelText);
+ icon.setImage(FooterArea.this.getMoreDetailsImage());
+ FooterArea.this.expandedPanel.dispose();
+ FooterArea.this.parent.pack();
+ } else {
+ label.setText(FooterArea.this.expandedLabelText);
+ icon.setImage(FooterArea.this.getFewerDetailsImage());
+ FooterArea.this.createExpandedPanel(numberOfColumnsParam);
+ FooterArea.this.parent.pack();
+ }
+ }
+ }
+ };
+
+ label.addListener(SWT.MouseUp, listener);
+ icon.addListener(SWT.MouseUp, listener);
+ }
+
+ /**
+ * Create a check box.
+ *
+ * @param numberOfColumns the number of columns
+ */
+ private void createCheckBox(final int numberOfColumns) {
+ final Button button = new Button(this.composite, SWT.CHECK);
+ button.setText(this.checkBoxLabel);
+ button.setSelection(this.checkBoxValue);
+ button.setBackground(this.getGreyColor());
+ button.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, true, false, numberOfColumns, 1));
+ button.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ FooterArea.this.checkBoxValue = button.getSelection();
+ }
+
+ });
+ }
+
+ /**
+ * Create footer section.
+ */
+ private void createFooter() {
+ this.createSeparator();
+
+ final Composite informationComposite = new Composite(this.parent.shell, SWT.NONE);
+ informationComposite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ informationComposite.setBackground(this.getGreyColor());
+
+ informationComposite.setLayout(new GridLayout(this.icon == null ? 1 : 2, false));
+
+ if (this.icon != null) {
+ final Label labelIcon = new Label(informationComposite, SWT.NONE);
+ labelIcon.setBackground(this.getGreyColor());
+ labelIcon.setImage(this.icon);
+ labelIcon.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
+ }
+ final Label labelText = new Label(informationComposite, SWT.NONE);
+ labelText.setBackground(this.getGreyColor());
+ labelText.setText(this.footerText);
+ labelText.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ }
+
+ /**
+ * Create the expanded panel.
+ *
+ * @param numberOfColumns the number of columns
+ */
+ private void createExpandedPanel(final int numberOfColumns) {
+ this.expandedPanel = new Text(this.composite, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
+ this.expandedPanel.setText(this.detailText);
+ this.expandedPanel.setBackground(this.getGreyColor());
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, false, false, numberOfColumns, 1);
+ gd.minimumHeight = gd.heightHint = 150;
+ this.expandedPanel.setLayoutData(gd);
+ }
+
+ /**
+ * Create a separator.
+ */
+ private void createSeparator() {
+ final Composite c = new Composite(this.parent.shell, SWT.NONE);
+ c.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+ c.setBackground(this.getGreyColor());
+
+ final GridLayout gridLayout = new GridLayout(1, false);
+ gridLayout.marginHeight = gridLayout.marginWidth = 0;
+ c.setLayout(gridLayout);
+
+ final Label separator = new Label(c, SWT.SEPARATOR | SWT.HORIZONTAL);
+ separator.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+
+ }
+
+ // ------------------------------------------- Getters & Setters
+
+ /**
+ * Gets the icon.
+ *
+ * @return the icon
+ */
+ public Image getIcon() {
+ return this.icon;
+ }
+
+ /**
+ * Sets the icon.
+ *
+ * @param icon the icon to set
+ * @return this footer area
+ */
+ public FooterArea setIcon(final Image icon) {
+ this.icon = icon;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the footer text.
+ *
+ * @return the text
+ */
+ public String getFooterText() {
+ return this.footerText;
+ }
+
+ /**
+ * Sets the footer text.
+ *
+ * @param text the text to set
+ * @return this footer area
+ */
+ public FooterArea setFooterText(final String text) {
+ this.footerText = text;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the button labels.
+ *
+ * @return the button labels
+ */
+ public List<String> getButtonLabels() {
+ return this.buttonLabels;
+ }
+
+ /**
+ * Sets the button labels.
+ *
+ * @param buttonLabels the button labels to set
+ * @return this footer area
+ */
+ public FooterArea setButtonLabels(final List<String> buttonLabels) {
+ this.buttonLabels = buttonLabels;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Sets the button labels.
+ *
+ * @param buttonLabels the button labels to set
+ * @return this footer area
+ */
+ public FooterArea setButtonLabels(final String... buttonLabels) {
+ this.buttonLabels = Arrays.asList(buttonLabels);
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the default button index.
+ *
+ * @return the default button index
+ */
+ public int getDefaultButtonIndex() {
+ return this.defaultButtonIndex;
+ }
+
+ /**
+ * Sets the default button index.
+ *
+ * @param defaultButtonIndex the default button index to set
+ * @return this footer area
+ */
+ public FooterArea setDefaultButtonIndex(final int defaultButtonIndex) {
+ this.defaultButtonIndex = defaultButtonIndex;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the timer.
+ *
+ * @return the timer value
+ */
+ public int getTimer() {
+ return this.timer;
+ }
+
+ /**
+ * Sets the timer.
+ *
+ * @param timer the timer value to set
+ * @return this footer area
+ */
+ public FooterArea setTimer(final int timer) {
+ this.timer = timer;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the timer index button.
+ *
+ * @return the timer index button
+ */
+ public int getTimerIndexButton() {
+ return this.timerIndexButton;
+ }
+
+ /**
+ * Sets the timer index button.
+ *
+ * @param timerIndexButton the timer index button to set
+ * @return this footer area
+ */
+ public FooterArea setTimerIndexButton(final int timerIndexButton) {
+ this.timerIndexButton = timerIndexButton;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the selected button.
+ *
+ * @return the selected button
+ */
+ int getSelectedButton() {
+ return this.selectedButtonIndex;
+ }
+
+ /**
+ * Gets the collapsed label text.
+ *
+ * @return the collapsed label text
+ */
+ public String getCollapsedLabelText() {
+ return this.collapsedLabelText;
+ }
+
+ /**
+ * Sets the collapsed label text.
+ *
+ * @param collapsedLabelText the collapsed label text to set
+ * @return this footer area
+ */
+ public FooterArea setCollapsedLabelText(final String collapsedLabelText) {
+ this.details = true;
+ this.collapsedLabelText = collapsedLabelText;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the expanded label text.
+ *
+ * @return the expanded label text
+ */
+ public String getExpandedLabelText() {
+ return this.expandedLabelText;
+ }
+
+ /**
+ * Sets the expanded label text.
+ *
+ * @param expandedLabelText the expanded label text to set
+ * @return this footer area
+ */
+ public FooterArea setExpandedLabelText(final String expandedLabelText) {
+ this.details = true;
+ this.expandedLabelText = expandedLabelText;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Checks if is expanded.
+ *
+ * @return the expanded flag
+ */
+ public boolean isExpanded() {
+ return this.expanded;
+ }
+
+ /**
+ * Sets the expanded.
+ *
+ * @param expanded the expanded flag to set
+ * @return this footer area
+ */
+ public FooterArea setExpanded(final boolean expanded) {
+ this.details = true;
+ this.expanded = expanded;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the detail text.
+ *
+ * @return the detail text
+ */
+ public String getDetailText() {
+ return this.detailText;
+ }
+
+ /**
+ * Sets the detail text.
+ *
+ * @param detailText the detail text to set
+ * @return this footer area
+ */
+ public FooterArea setDetailText(final String detailText) {
+ this.details = true;
+ this.detailText = detailText;
+ this.setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the check box value.
+ *
+ * @return the check box vqlue
+ */
+ public boolean getCheckBoxValue() {
+ return this.checkBoxValue;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/MessageArea.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/MessageArea.java
new file mode 100644
index 0000000..56c7b58
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/opalDialog/MessageArea.java
@@ -0,0 +1,690 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+package org.mihalis.opal.opalDialog;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+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.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.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.utils.ReadOnlyStyledText;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+import org.mihalis.opal.utils.StringUtil;
+
+/**
+ * Instances of this class are message areas.
+ */
+public class MessageArea extends DialogArea {
+
+ /** The Constant DEFAULT_MIN_HEIGHT_FOR_EXCEPTIONS. */
+ private static final int DEFAULT_MIN_HEIGHT_FOR_EXCEPTIONS = 300;
+
+ /** The Constant INDENT_NO_ICON. */
+ private static final int INDENT_NO_ICON = 8;
+
+ /** The Constant DEFAULT_MARGIN. */
+ private static final int DEFAULT_MARGIN = 10;
+
+ /** The composite. */
+ // Main composite
+ private Composite composite;
+
+ /** The title. */
+ // Informations for a simple dialog box
+ private String title;
+
+ /** The icon. */
+ private Image icon;
+
+ /** The text. */
+ private String text;
+
+ /** The radio choice. */
+ // Informations for a radio choice dialog box
+ private int radioChoice;
+
+ /** The radio default selection. */
+ private int radioDefaultSelection;
+
+ /** The radio values. */
+ private String[] radioValues;
+
+ /** The exception. */
+ // Informations for a exception viewer dialog box
+ private Throwable exception;
+
+ /** The text exception. */
+ private Text textException;
+
+ /** The text box value. */
+ // Informations for an input dialog box
+ private String textBoxValue;
+
+ /** The choice. */
+ // Informations for a choice dialog box
+ private int choice;
+
+ /** The choice default selection. */
+ private int choiceDefaultSelection;
+
+ /** The choice values. */
+ private ChoiceItem[] choiceValues;
+
+ /** The progress bar. */
+ // Informations for a progress bar displayed in a dialog box
+ private ProgressBar progressBar;
+
+ /** The progress bar minimum value. */
+ private int progressBarMinimumValue;
+
+ /** The progress bar maximum value. */
+ private int progressBarMaximumValue;
+
+ /** The progress bar value. */
+ private int progressBarValue;
+
+ /** The vertical scrollbar. */
+ private boolean verticalScrollbar = false;
+
+ /** The height. */
+ private int height = -1;
+
+ /** The label. */
+ private StyledText label;
+
+ /**
+ * Constructor.
+ *
+ * @param parent dialog that is composed of this message area
+ */
+ public MessageArea(final Dialog parent) {
+ super(parent);
+ this.radioChoice = -1;
+ this.choice = -1;
+ this.progressBarValue = -1;
+ }
+
+ /**
+ * Add a choice.
+ *
+ * @param defaultSelection default selection
+ * @param items a list of the choice item
+ * @return the current message area
+ */
+ public MessageArea addChoice(final int defaultSelection, final ChoiceItem... items) {
+ setInitialised(true);
+ this.choiceDefaultSelection = defaultSelection;
+ this.choiceValues = items;
+ return this;
+ }
+
+ /**
+ * Add a choice composed of radio buttons.
+ *
+ * @param defaultSelection default selection
+ * @param values values
+ * @return the current message area
+ */
+ public MessageArea addRadioButtons(final int defaultSelection, final String... values) {
+ setInitialised(true);
+ this.radioDefaultSelection = defaultSelection;
+ this.radioValues = values;
+ return this;
+ }
+
+ /**
+ * Add a text box for input.
+ *
+ * @param value defaut value of the textbox
+ * @return the current message area
+ */
+ public MessageArea addTextBox(final String value) {
+ setInitialised(true);
+ this.textBoxValue = value;
+ return this;
+ }
+
+ /**
+ * Add a progress bar.
+ *
+ * @param mininum minimum value
+ * @param maximum maximum value
+ * @param value default value
+ * @return the current message area
+ */
+ public MessageArea addProgressBar(final int mininum, final int maximum, final int value) {
+ setInitialised(true);
+ this.progressBarMinimumValue = mininum;
+ this.progressBarMaximumValue = maximum;
+ this.progressBarValue = value;
+ return this;
+ }
+
+ /**
+ * Render.
+ *
+ * @see org.mihalis.opal.OpalDialog.DialogArea#render()
+ */
+ @Override
+ public void render() {
+ if (!isInitialised()) {
+ return;
+ }
+
+ this.composite = new Composite(this.parent.shell, SWT.NONE);
+ this.composite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+ this.composite.setBackground(this.composite.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+
+ final boolean hasIcon = this.icon != null;
+ final boolean hasTitle = !StringUtil.isEmpty(this.title);
+ final boolean hasText = !StringUtil.isEmpty(this.text);
+ final boolean hasRadio = this.radioValues != null;
+ final boolean hasException = this.exception != null;
+ final boolean hasTextbox = this.textBoxValue != null;
+ final boolean hasChoice = this.choiceValues != null;
+ final boolean hasProgressBar = this.progressBarValue != -1;
+
+ final int numberOfColumns = hasIcon ? 2 : 1;
+ int numberOfRows = hasTitle && hasText ? 2 : 1;
+
+ if (hasRadio) {
+ numberOfRows += this.radioValues.length;
+ }
+
+ if (hasChoice) {
+ numberOfRows += this.choiceValues.length;
+ }
+
+ if (hasException || hasTextbox) {
+ numberOfRows++;
+ }
+
+ if (hasProgressBar) {
+ numberOfRows++;
+ }
+
+ final GridLayout gridLayout = new GridLayout(numberOfColumns, false);
+ gridLayout.marginHeight = gridLayout.marginWidth = 0;
+ gridLayout.marginRight = DEFAULT_MARGIN;
+ gridLayout.marginLeft = DEFAULT_MARGIN;
+ gridLayout.marginTop = DEFAULT_MARGIN;
+ gridLayout.marginBottom = DEFAULT_MARGIN;
+ this.composite.setLayout(gridLayout);
+
+ if (hasIcon) {
+ createIcon(numberOfRows);
+ }
+
+ if (hasTitle) {
+ createTitle(hasIcon);
+ }
+
+ if (hasText) {
+ createText(hasIcon, hasTitle);
+ }
+
+ if (hasRadio) {
+ createRadioButtons();
+ }
+
+ if (hasException) {
+ createTextException();
+ }
+
+ if (hasTextbox) {
+ createTextBox();
+ }
+
+ if (hasChoice) {
+ createChoice();
+ }
+
+ if (hasProgressBar) {
+ createProgressBar();
+ }
+
+ }
+
+ /**
+ * Create the icon.
+ *
+ * @param numberOfRows number of rows displayed
+ */
+ private void createIcon(final int numberOfRows) {
+ final Label label = new Label(this.composite, SWT.NONE);
+ label.setImage(this.icon);
+ label.setBackground(this.composite.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ label.setLayoutData(new GridData(GridData.CENTER, GridData.BEGINNING, false, false, 1, numberOfRows));
+ }
+
+ /**
+ * Create the title.
+ *
+ * @param hasIcon if <code>true</code> an icon is displayed
+ */
+ private void createTitle(final boolean hasIcon) {
+ final Label label = new Label(this.composite, SWT.NONE);
+ label.setText(this.title);
+ label.setFont(getBiggerFont());
+ label.setForeground(getTitleColor());
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ final GridData gd = new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1);
+
+ if (hasIcon) {
+ gd.horizontalIndent = INDENT_NO_ICON;
+ } else {
+ gd.horizontalIndent = DEFAULT_MARGIN;
+ gd.verticalIndent = DEFAULT_MARGIN;
+ }
+
+ label.setLayoutData(gd);
+ }
+
+ /**
+ * Create the text.
+ *
+ * @param hasIcon if <code>true</code> an icon is displayed
+ * @param hasTitle if <code>true</code> a title is displayed
+ */
+ private void createText(final boolean hasIcon, final boolean hasTitle) {
+
+ this.label = new ReadOnlyStyledText(this.composite, SWT.NONE | (this.verticalScrollbar ? SWT.V_SCROLL : SWT.NONE));
+ this.label.setText(this.text);
+ SWTGraphicUtil.applyHTMLFormating(this.label);
+ this.label.setEditable(false);
+ this.label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true, 1, 1);
+ if (this.height != -1) {
+ gd.heightHint = this.height;
+ }
+
+ if (hasIcon) {
+ gd.horizontalIndent = INDENT_NO_ICON;
+ } else {
+ gd.horizontalIndent = DEFAULT_MARGIN * 2;
+ if (hasTitle) {
+ gd.verticalIndent = INDENT_NO_ICON;
+ } else {
+ gd.verticalIndent = DEFAULT_MARGIN * 2;
+ }
+ }
+
+ this.label.setLayoutData(gd);
+ }
+
+ /**
+ * Create radio buttons.
+ */
+ private void createRadioButtons() {
+ for (int i = 0; i < this.radioValues.length; i++) {
+ final Button button = new Button(this.composite, SWT.RADIO);
+ button.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ button.setText(this.radioValues[i]);
+
+ final Integer index = Integer.valueOf(i);
+ button.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ if (button.getSelection()) {
+ MessageArea.this.radioChoice = index.intValue();
+ }
+ }
+
+ });
+
+ button.setSelection(i == this.radioDefaultSelection);
+ final GridData gd = new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1);
+ gd.horizontalIndent = DEFAULT_MARGIN;
+ button.setLayoutData(gd);
+ }
+ }
+
+ /**
+ * Create the text that displays an exception.
+ */
+ private void createTextException() {
+ this.textException = new Text(this.composite, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
+ this.textException.setText(StringUtil.stackStraceAsString(this.exception));
+ this.textException.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true, 1, 1);
+ gd.minimumHeight = DEFAULT_MIN_HEIGHT_FOR_EXCEPTIONS;
+ this.textException.setLayoutData(gd);
+ }
+
+ /**
+ * Create a text box.
+ */
+ private void createTextBox() {
+ final Text textbox = new Text(this.composite, SWT.BORDER);
+ textbox.setText(this.textBoxValue);
+ textbox.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true, 1, 1);
+ textbox.setLayoutData(gd);
+ textbox.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(final ModifyEvent e) {
+ MessageArea.this.textBoxValue = textbox.getText();
+ }
+ });
+
+ textbox.addListener(SWT.KeyUp, new Listener() {
+
+ @Override
+ public void handleEvent(final Event e) {
+ if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
+ MessageArea.this.parent.shell.dispose();
+ MessageArea.this.parent.getFooterArea().selectedButtonIndex = 0;
+ }
+
+ }
+ });
+
+ textbox.getShell().addListener(SWT.Activate, new Listener() {
+
+ @Override
+ public void handleEvent(final Event arg0) {
+ textbox.forceFocus();
+ textbox.setSelection(textbox.getText().length());
+ textbox.getShell().removeListener(SWT.Activate, this);
+ }
+ });
+
+ }
+
+ /**
+ * Create a choice selection.
+ */
+ private void createChoice() {
+ for (int i = 0; i < this.choiceValues.length; i++) {
+ final ChoiceWidget choice = new ChoiceWidget(this.composite, SWT.RADIO);
+ choice.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ choice.setChoiceItem(this.choiceValues[i]);
+
+ final Integer index = Integer.valueOf(i);
+ choice.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ MessageArea.this.choice = index.intValue();
+ MessageArea.this.parent.shell.dispose();
+ }
+
+ });
+
+ choice.setSelection(i == this.choiceDefaultSelection);
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, false, false, 1, 1);
+ choice.setLayoutData(gd);
+ }
+ }
+
+ /**
+ * Create a progress bar.
+ */
+ private void createProgressBar() {
+ this.progressBar = new ProgressBar(this.composite, SWT.SMOOTH | SWT.HORIZONTAL);
+ this.progressBar.setMinimum(this.progressBarMinimumValue);
+ this.progressBar.setMaximum(this.progressBarMaximumValue);
+ this.progressBar.setSelection(this.progressBarValue);
+ this.progressBar.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, false, 1, 1);
+ this.progressBar.setLayoutData(gd);
+ }
+
+ /**
+ * Hide the exception panel.
+ */
+ void hideException() {
+ this.textException.dispose();
+ this.parent.pack();
+ }
+
+ /**
+ * Show the exception panel.
+ */
+ void showException() {
+ createTextException();
+ this.parent.pack();
+ }
+
+ // ------------------------------------------- Getters & Setters
+
+ /**
+ * Gets the title.
+ *
+ * @return the title
+ */
+ public String getTitle() {
+ return this.title;
+ }
+
+ /**
+ * Sets the title.
+ *
+ * @param title the title to set
+ * @return the current message area
+ */
+ public MessageArea setTitle(final String title) {
+ this.title = title;
+ setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the icon.
+ *
+ * @return the icon
+ */
+ public Image getIcon() {
+ return this.icon;
+ }
+
+ /**
+ * Sets the icon.
+ *
+ * @param icon the icon to set
+ * @return the message area
+ */
+ public MessageArea setIcon(final Image icon) {
+ this.icon = icon;
+ setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @return the text
+ */
+ public String getText() {
+ return this.text;
+ }
+
+ /**
+ * Sets the text.
+ *
+ * @param text the text to set
+ * @return the message area
+ */
+ public MessageArea setText(final String text) {
+ this.text = text;
+ setInitialised(true);
+ if (this.progressBar != null && this.label != null && !this.label.isDisposed()) {
+ this.label.setText(text);
+ SWTGraphicUtil.applyHTMLFormating(this.label);
+ }
+ return this;
+ }
+
+ /**
+ * Gets the radio choice.
+ *
+ * @return the radio choice
+ */
+ public int getRadioChoice() {
+ return this.radioChoice;
+ }
+
+ /**
+ * Gets the exception.
+ *
+ * @return the exception
+ */
+ public Throwable getException() {
+ return this.exception;
+ }
+
+ /**
+ * Sets the exception.
+ *
+ * @param exception the exception to set
+ * @return the message area
+ */
+ public MessageArea setException(final Throwable exception) {
+ this.exception = exception;
+ setInitialised(true);
+ return this;
+ }
+
+ /**
+ * Gets the choice.
+ *
+ * @return the choice
+ */
+ public int getChoice() {
+ return this.choice;
+ }
+
+ /**
+ * Gets the text box value.
+ *
+ * @return the value stored in the text box
+ */
+ public String getTextBoxValue() {
+ return this.textBoxValue;
+ }
+
+ /**
+ * Gets the progress bar minimum value.
+ *
+ * @return the progress bar minimum value
+ */
+ public int getProgressBarMinimumValue() {
+ return this.progressBarMinimumValue;
+ }
+
+ /**
+ * Sets the progress bar minimum value.
+ *
+ * @param progressBarMinimumValue the progress bar minimum value to set
+ */
+ public void setProgressBarMinimumValue(final int progressBarMinimumValue) {
+ this.progressBarMinimumValue = progressBarMinimumValue;
+ if (this.progressBar != null && !this.progressBar.isDisposed()) {
+ this.progressBar.setMinimum(progressBarMinimumValue);
+ }
+ }
+
+ /**
+ * Gets the progress bar maximum value.
+ *
+ * @return the progress bar maximum value
+ */
+ public int getProgressBarMaximumValue() {
+ return this.progressBarMaximumValue;
+ }
+
+ /**
+ * Sets the progress bar maximum value.
+ *
+ * @param progressBarMaximumValue the progress bar minimum value to set
+ */
+ public void setProgressBarMaximumValue(final int progressBarMaximumValue) {
+ this.progressBarMaximumValue = progressBarMaximumValue;
+ if (this.progressBar != null && !this.progressBar.isDisposed()) {
+ this.progressBar.setMaximum(progressBarMaximumValue);
+ }
+ }
+
+ /**
+ * Gets the progress bar value.
+ *
+ * @return the progress bar value
+ */
+ public int getProgressBarValue() {
+ return this.progressBarValue;
+ }
+
+ /**
+ * Sets the progress bar value.
+ *
+ * @param progressBarValue the progress bar value to set
+ */
+ public void setProgressBarValue(final int progressBarValue) {
+ this.progressBarValue = progressBarValue;
+ if (this.progressBar != null && !this.progressBar.isDisposed()) {
+ this.progressBar.setSelection(progressBarValue);
+ }
+ }
+
+ /**
+ * Checks if is vertical scrollbar.
+ *
+ * @return the verticalScrollbar
+ */
+ public boolean isVerticalScrollbar() {
+ return this.verticalScrollbar;
+ }
+
+ /**
+ * Sets the vertical scrollbar.
+ *
+ * @param verticalScrollbar the verticalScrollbar to set
+ */
+ public void setVerticalScrollbar(final boolean verticalScrollbar) {
+ this.verticalScrollbar = verticalScrollbar;
+ }
+
+ /**
+ * Gets the height.
+ *
+ * @return the height
+ */
+ public int getHeight() {
+ return this.height;
+ }
+
+ /**
+ * Sets the height.
+ *
+ * @param height the height to set
+ */
+ public void setHeight(final int height) {
+ this.height = height;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/panels/BlurredPanel.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/panels/BlurredPanel.java
new file mode 100644
index 0000000..2376c23
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/panels/BlurredPanel.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * 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.panels;
+
+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.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are controls located on the top of a shell. They
+ * display a blurred version of the content of the shell
+ */
+public class BlurredPanel {
+
+ /** The parent. */
+ private final Shell parent;
+
+ /** The Constant BLURED_PANEL_KEY. */
+ private static final String BLURED_PANEL_KEY = "org.mihalis.opal.Panels.DarkPanel";
+
+ /** The radius. */
+ private int radius;
+
+ /** The panel. */
+ private Shell panel;
+
+ /** The canvas. */
+ private Canvas canvas;
+
+ /**
+ * Constructs a new instance of this class given its parent.
+ *
+ * @param shell a shell that will be the parent of the new instance (cannot
+ * 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 parent has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ public BlurredPanel(final Shell shell) {
+ if (shell == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (shell.isDisposed()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ this.parent = shell;
+ if (shell.getData(BLURED_PANEL_KEY) != null) {
+ throw new IllegalArgumentException("This shell has already an infinite panel attached on it !");
+ }
+ shell.setData(BLURED_PANEL_KEY, this);
+ this.radius = 2;
+ }
+
+ /**
+ * Show the blurred panel.
+ */
+ public void show() {
+ if (this.parent.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ this.panel = new Shell(this.parent, SWT.APPLICATION_MODAL | SWT.NO_TRIM);
+ this.panel.setLayout(new FillLayout());
+
+ this.panel.addListener(SWT.KeyUp, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ event.doit = false;
+ }
+ });
+
+ this.canvas = new Canvas(this.panel, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
+ this.canvas.addPaintListener(new PaintListener() {
+
+ @Override
+ public void paintControl(final PaintEvent e) {
+ paintCanvas(e);
+ }
+ });
+
+ this.panel.setBounds(this.panel.getDisplay().map(this.parent, null, this.parent.getClientArea()));
+ this.panel.open();
+
+ }
+
+ /**
+ * Paint the canvas that holds the panel.
+ *
+ * @param e {@link PaintEvent}
+ */
+ private void paintCanvas(final PaintEvent e) {
+ // Paint the panel
+ e.gc.drawImage(createBlurredImage(), 0, 0);
+ }
+
+ /**
+ * Creates the blurred image.
+ *
+ * @return the image
+ */
+ private Image createBlurredImage() {
+ final GC gc = new GC(this.parent);
+ final Image image = new Image(this.parent.getDisplay(), this.parent.getSize().x, this.parent.getSize().y);
+ gc.copyArea(image, 0, 0);
+ gc.dispose();
+
+ return new Image(this.parent.getDisplay(), SWTGraphicUtil.blur(image.getImageData(), this.radius));
+
+ }
+
+ /**
+ * Hide the panel.
+ */
+ public void hide() {
+ if (this.parent.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ if (this.panel == null || this.panel.isDisposed()) {
+ return;
+ }
+
+ this.panel.dispose();
+ }
+
+ /**
+ * Gets the radius.
+ *
+ * @return the radius of the blur effect
+ */
+ public int getRadius() {
+ return this.radius;
+ }
+
+ /**
+ * Sets the radius.
+ *
+ * @param radius the radius to set
+ */
+ public void setRadius(final int radius) {
+ this.radius = radius;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/panels/DarkPanel.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/panels/DarkPanel.java
new file mode 100644
index 0000000..520889f
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/panels/DarkPanel.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * 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.panels;
+
+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.GC;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Instances of this class are controls located on the top of a shell. They
+ * display a dark panel on this shell
+ */
+public class DarkPanel {
+
+ /** The parent. */
+ private final Shell parent;
+
+ /** The Constant DARK_PANEL_KEY. */
+ private static final String DARK_PANEL_KEY = "org.mihalis.opal.BluredPanel.DarkPanel";
+
+ /** The alpha. */
+ private int alpha;
+
+ /** The panel. */
+ private Shell panel;
+
+ /** The canvas. */
+ private Canvas canvas;
+
+ /**
+ * Constructs a new instance of this class given its parent.
+ *
+ * @param shell a shell that will be the parent of the new instance (cannot
+ * 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 parent has been
+ * disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * </ul>
+ */
+ public DarkPanel(final Shell shell) {
+ if (shell == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ if (shell.isDisposed()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ this.parent = shell;
+ if (shell.getData(DARK_PANEL_KEY) != null) {
+ throw new IllegalArgumentException("This shell has already an infinite panel attached on it !");
+ }
+ shell.setData(DARK_PANEL_KEY, this);
+ this.alpha = 100;
+ }
+
+ /**
+ * Show the dark panel.
+ */
+ public void show() {
+ if (this.parent.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ this.panel = new Shell(this.parent, SWT.APPLICATION_MODAL | SWT.NO_TRIM);
+ this.panel.setLayout(new FillLayout());
+ this.panel.setAlpha(this.alpha);
+
+ this.panel.addListener(SWT.KeyUp, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ event.doit = false;
+ }
+ });
+
+ this.canvas = new Canvas(this.panel, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
+ this.canvas.addPaintListener(new PaintListener() {
+
+ @Override
+ public void paintControl(final PaintEvent e) {
+ paintCanvas(e);
+ }
+ });
+
+ this.panel.setBounds(this.panel.getDisplay().map(this.parent, null, this.parent.getClientArea()));
+ this.panel.open();
+
+ }
+
+ /**
+ * Paint the canvas that holds the panel.
+ *
+ * @param e {@link PaintEvent}
+ */
+ private void paintCanvas(final PaintEvent e) {
+ // Paint the panel
+ final Rectangle clientArea = ((Canvas) e.widget).getClientArea();
+ final GC gc = e.gc;
+ gc.setBackground(this.panel.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ gc.fillRectangle(clientArea);
+ }
+
+ /**
+ * Hide the dark panel.
+ */
+ public void hide() {
+ if (this.parent.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ if (this.panel == null || this.panel.isDisposed()) {
+ return;
+ }
+
+ this.panel.dispose();
+ }
+
+ /**
+ * Gets the alpha.
+ *
+ * @return the alpha value
+ */
+ public int getAlpha() {
+ return this.alpha;
+ }
+
+ /**
+ * Sets the alpha.
+ *
+ * @param alpha the alpha to set
+ */
+ public void setAlpha(final int alpha) {
+ this.alpha = alpha;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWContainer.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWContainer.java
new file mode 100644
index 0000000..0805a2e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWContainer.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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.preferenceWindow;
+
+import org.eclipse.swt.widgets.Composite;
+import org.mihalis.opal.preferenceWindow.widgets.PWWidget;
+
+/**
+ * Abstract class for "Containers" (row, group and tab).
+ */
+public abstract class PWContainer {
+
+ /**
+ * Add a container to the current element.
+ *
+ * @param element element to add
+ * @return the container
+ */
+ public abstract PWContainer add(final PWContainer element);
+
+ /**
+ * Add a widget to the current element.
+ *
+ * @param widget widget to add
+ * @return the container
+ */
+ public abstract PWContainer add(final PWWidget widget);
+
+ /**
+ * Build the content of the container.
+ *
+ * @param parent parent composite
+ */
+ public abstract void build(final Composite parent);
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWGroup.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWGroup.java
new file mode 100644
index 0000000..e77e4d5
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWGroup.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * 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.preferenceWindow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+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.Group;
+import org.mihalis.opal.preferenceWindow.widgets.PWWidget;
+
+/**
+ * Instances of this class are groups.
+ */
+public class PWGroup extends PWRowGroup {
+
+ /** The label. */
+ private final String label;
+
+ /** The has border. */
+ private final boolean hasBorder;
+
+ /** The children. */
+ private final List<PWRow> children;
+
+ /**
+ * Constructor.
+ *
+ * @param hasBorder if <code>true</code>, the group has a border
+ */
+ public PWGroup(final boolean hasBorder) {
+ this(null, hasBorder);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param label label associated to the group
+ */
+ public PWGroup(final String label) {
+ this(label, true);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param label label associated to the group
+ * @param hasBorder if <code>true</code>, the group has a border
+ */
+ public PWGroup(final String label, final boolean hasBorder) {
+ this.label = label;
+ this.hasBorder = hasBorder;
+ this.children = new ArrayList<PWRow>();
+ }
+
+ /**
+ * Adds the.
+ *
+ * @param element the element
+ * @return the PW container
+ * @see org.mihalis.opal.preferenceWindow.PWContainer#add(org.mihalis.opal.preferenceWindow.PWContainer)
+ */
+ @Override
+ public PWContainer add(final PWContainer element) {
+ if (!(element instanceof PWRow)) {
+ throw new UnsupportedOperationException("Can only add a PWRow.");
+ }
+ this.children.add((PWRow) element);
+ return this;
+ }
+
+ /**
+ * Adds the.
+ *
+ * @param widget the widget
+ * @return the PW container
+ * @see org.mihalis.opal.preferenceWindow.PWContainer#add(org.mihalis.opal.preferenceWindow.widgets.PWWidget)
+ */
+ @Override
+ public PWContainer add(final PWWidget widget) {
+ final PWRow row = new PWRow();
+ row.add(widget);
+ this.children.add(row);
+ return this;
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @see org.mihalis.opal.preferenceWindow.PWContainer#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void build(final Composite parent) {
+ final Composite composite;
+ if (this.hasBorder) {
+ composite = new Group(parent, SWT.NONE);
+ if (this.label != null && !this.label.trim().equals("")) {
+ ((Group) composite).setText(this.label);
+ }
+ } else {
+ composite = new Composite(parent, SWT.BORDER);
+ }
+
+ final int numCol = computeNumberOfColumns();
+
+ composite.setLayout(new GridLayout(numCol, false));
+ composite.setLayoutData(new GridData(GridData.BEGINNING, GridData.FILL, false, false, this.parentNumberOfColums, 1));
+
+ for (final PWRow row : this.children) {
+ row.setParentNumberOfColumns(numCol);
+ row.build(composite);
+ }
+
+ }
+
+ /**
+ * Compute number of columns.
+ *
+ * @return the int
+ */
+ private int computeNumberOfColumns() {
+ int numberOfColumns = 1;
+ for (final PWRow row : this.children) {
+ numberOfColumns = Math.max(numberOfColumns, row.getNumberOfColums());
+ }
+ return numberOfColumns;
+ }
+
+ /**
+ * Check parent.
+ *
+ * @param parent the parent
+ * @see org.mihalis.opal.preferenceWindow.PWRowGroup#checkParent(org.mihalis.opal.preferenceWindow.PWContainer)
+ */
+ @Override
+ protected void checkParent(final PWContainer parent) {
+ if (parent instanceof PWTab) {
+ return;
+ }
+ throw new UnsupportedOperationException("Bad parent, should be only PWTab ");
+ }
+
+ /**
+ * Enable or disable.
+ *
+ * @see org.mihalis.opal.preferenceWindow.PWRowGroup#enableOrDisable()
+ */
+ @Override
+ public void enableOrDisable() {
+ if (this.enabler == null) {
+ return;
+ }
+
+ final boolean enabled = this.enabler.isEnabled();
+ for (final PWRow row : this.children) {
+ enableOrDisable(row, enabled);
+ }
+ }
+
+ /**
+ * Enable or disable a row.
+ *
+ * @param row row to enable or disable
+ * @param enabled enable flag
+ */
+ private void enableOrDisable(final PWRow row, final boolean enabled) {
+ for (final PWWidget widget : row.widgets) {
+ final boolean widgetEnable = widget.enableOrDisable();
+
+ for (final Control c : widget.getControls()) {
+ if (!c.isDisposed()) {
+ c.setEnabled(enabled && widgetEnable);
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWRow.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWRow.java
new file mode 100644
index 0000000..72ac297
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWRow.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * 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.preferenceWindow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.mihalis.opal.preferenceWindow.widgets.PWButton;
+import org.mihalis.opal.preferenceWindow.widgets.PWLabel;
+import org.mihalis.opal.preferenceWindow.widgets.PWWidget;
+
+/**
+ * Instances of this class are rows.
+ */
+public class PWRow extends PWRowGroup {
+
+ /** The widgets. */
+ protected final List<PWWidget> widgets;
+
+ /**
+ * Constructor.
+ */
+ public PWRow() {
+ this.widgets = new ArrayList<PWWidget>();
+ }
+
+ /**
+ * Adds the.
+ *
+ * @param widget the widget
+ * @return the PW container
+ * @see org.mihalis.opal.preferenceWindow.PWContainer#add(org.mihalis.opal.preferenceWindow.widgets.PWWidget)
+ */
+ @Override
+ public PWContainer add(final PWWidget widget) {
+ this.widgets.add(widget);
+ addColumn(widget.getNumberOfColumns());
+ return this;
+ }
+
+ /**
+ * Adds the.
+ *
+ * @param element the element
+ * @return the PW container
+ * @see org.mihalis.opal.preferenceWindow.PWContainer#add(org.mihalis.opal.preferenceWindow.PWContainer)
+ */
+ @Override
+ public PWContainer add(final PWContainer element) {
+ if (element instanceof PWRow || element instanceof PWGroup) {
+ return this.parent.add(element);
+ } else {
+ throw new UnsupportedOperationException("Can only add a PWGroup or a PWRow.");
+ }
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @see org.mihalis.opal.preferenceWindow.PWContainer#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void build(final Composite parent) {
+ final int size = this.widgets.size();
+ int columIndex = 0;
+ for (int i = 0; i < size; i++) {
+ final PWWidget widget = this.widgets.get(i);
+ final Control control = widget.checkAndBuild(parent);
+ if (control != null && control.getLayoutData() == null) {
+ final int colSpan;
+ final boolean grabExcessSpace;
+ final int alignment;
+ if (size == 1) {
+ if (widget.isSingleWidget()) {
+ colSpan = this.parentNumberOfColums;
+ } else {
+ colSpan = this.parentNumberOfColums - widget.getNumberOfColumns() + 1;
+ }
+ grabExcessSpace = true;
+ } else {
+ if (i == size - 1) {
+ colSpan = this.parentNumberOfColums - columIndex;
+ grabExcessSpace = widget.isGrabExcessSpace();
+ } else {
+ colSpan = 1;
+ grabExcessSpace = widget instanceof PWButton && i == 0 ? true : widget.isGrabExcessSpace();
+ }
+ }
+ columIndex += widget.getNumberOfColumns();
+
+ if (i == 0 && grabExcessSpace && size > 1) {
+ if (widget instanceof PWLabel || widget instanceof PWButton) {
+ alignment = GridData.END;
+ } else {
+ alignment = GridData.BEGINNING;
+ }
+ } else {
+ alignment = widget.getAlignment();
+ }
+
+ final GridData gd = new GridData(alignment, GridData.BEGINNING, grabExcessSpace, false, colSpan, 1);
+ gd.horizontalIndent = widget.getIndent();
+ gd.widthHint = widget.getWidth();
+ if (widget.getHeight() != -1) {
+ gd.heightHint = widget.getHeight();
+ }
+ control.setLayoutData(gd);
+ }
+ }
+ }
+
+ /**
+ * Check parent.
+ *
+ * @param parent the parent
+ * @see org.mihalis.opal.preferenceWindow.PWRowGroup#checkParent(org.mihalis.opal.preferenceWindow.PWContainer)
+ */
+ @Override
+ protected void checkParent(final PWContainer parent) {
+ if (parent instanceof PWTab || parent instanceof PWGroup) {
+ return;
+ }
+ throw new UnsupportedOperationException("Bad parent, should be only PWTab or PWGroup");
+ }
+
+ /**
+ * Enable or disable.
+ *
+ * @see org.mihalis.opal.preferenceWindow.PWRowGroup#enableOrDisable()
+ */
+ @Override
+ public void enableOrDisable() {
+ if (this.enabler == null) {
+ return;
+ }
+
+ final boolean enabled = this.enabler.isEnabled();
+ for (final PWWidget widget : this.widgets) {
+ final boolean widgetEnable = widget.enableOrDisable();
+ for (final Control c : widget.getControls()) {
+ if (!c.isDisposed()) {
+ c.setEnabled(enabled && widgetEnable);
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWRowGroup.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWRowGroup.java
new file mode 100644
index 0000000..7824ff3
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWRowGroup.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * 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.preferenceWindow;
+
+import org.mihalis.opal.preferenceWindow.enabler.Enabler;
+
+/**
+ * Abstract class for both row and groups.
+ */
+public abstract class PWRowGroup extends PWContainer {
+
+ /** The number of columns. */
+ protected int numberOfColumns;
+
+ /** The parent number of colums. */
+ protected int parentNumberOfColums;
+
+ /** The parent. */
+ protected PWContainer parent;
+
+ /** The enabler. */
+ protected Enabler enabler;
+
+ /**
+ * Check if the parent is compatible with the object.
+ *
+ * @param parent parent to check
+ * @throws UnsupportedOperationException if the parent is not compatible
+ * with the object
+ */
+ protected abstract void checkParent(PWContainer parent);
+
+ /**
+ * Enables or disables all elements stored in this group or row.
+ */
+ public abstract void enableOrDisable();
+
+ /**
+ * Add a column to the current element.
+ *
+ * @param number number of column to add
+ */
+ public void addColumn(final int number) {
+ this.numberOfColumns += number;
+ }
+
+ /**
+ * Gets the number of colums.
+ *
+ * @return the number of columns of this group or row
+ */
+ public int getNumberOfColums() {
+ return this.numberOfColumns;
+ }
+
+ /**
+ * Sets the enabler.
+ *
+ * @param enabler the enabler to set
+ * @return the PW row group
+ */
+ public PWRowGroup setEnabler(final Enabler enabler) {
+ this.enabler = enabler;
+ this.enabler.injectRowGroup(this);
+ return this;
+ }
+
+ /**
+ * Sets the parent.
+ *
+ * @param parent the parent to set
+ */
+ public void setParent(final PWContainer parent) {
+ checkParent(parent);
+ this.parent = parent;
+ }
+
+ /**
+ * Sets the parent number of columns.
+ *
+ * @param numberOfColumns the number of columns of the parent
+ */
+ public void setParentNumberOfColumns(final int numberOfColumns) {
+ this.parentNumberOfColums = numberOfColumns;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWTab.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWTab.java
new file mode 100644
index 0000000..2c75d29
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWTab.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * 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.preferenceWindow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.mihalis.opal.preferenceWindow.widgets.PWWidget;
+
+/**
+ * Instance of this class are tabs.
+ */
+public class PWTab extends PWContainer {
+
+ /** The image. */
+ private final Image image;
+
+ /** The text. */
+ private final String text;
+
+ /** The children. */
+ private final List<PWRowGroup> children;
+
+ /**
+ * Constructor.
+ *
+ * @param image image associated to the tab
+ * @param text text associated to the tab
+ */
+ PWTab(final Image image, final String text) {
+ this.image = image;
+ this.text = text;
+ this.children = new ArrayList<PWRowGroup>();
+ }
+
+ /**
+ * Adds the.
+ *
+ * @param element the element
+ * @return the PW container
+ * @see org.mihalis.opal.preferenceWindow.PWContainer#add(org.mihalis.opal.preferenceWindow.PWContainer)
+ */
+ @Override
+ public PWContainer add(final PWContainer element) {
+ if (!(element instanceof PWGroup) && !(element instanceof PWRow)) {
+ throw new UnsupportedOperationException("Can only add a PWGroup or a PWRow.");
+ }
+ ((PWRowGroup) element).setParent(this);
+ this.children.add((PWRowGroup) element);
+ return this;
+ }
+
+ /**
+ * Adds the.
+ *
+ * @param widget the widget
+ * @return the PW container
+ * @see org.mihalis.opal.preferenceWindow.PWContainer#add(org.mihalis.opal.preferenceWindow.widgets.PWWidget)
+ */
+ @Override
+ public PWContainer add(final PWWidget widget) {
+ final PWRow row = new PWRow();
+ row.setParent(this);
+ row.add(widget);
+ this.children.add(row);
+ return this;
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @see org.mihalis.opal.preferenceWindow.PWContainer#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void build(final Composite parent) {
+ final int numberOfColumns = computeNumberOfColums();
+ parent.setLayout(new GridLayout(numberOfColumns, false));
+
+ for (final PWRowGroup rowGroup : this.children) {
+ rowGroup.setParentNumberOfColumns(numberOfColumns);
+ rowGroup.build(parent);
+ }
+
+ PreferenceWindow.getInstance().fireEnablers();
+
+ }
+
+ /**
+ * Compute number of colums.
+ *
+ * @return the total number of columns in this tab
+ */
+ private int computeNumberOfColums() {
+ int numberOfColumns = 1;
+ for (final PWRowGroup rowGroup : this.children) {
+ if (rowGroup instanceof PWRow) {
+ numberOfColumns = Math.max(numberOfColumns, rowGroup.getNumberOfColums());
+ }
+ }
+ return numberOfColumns;
+ }
+
+ /**
+ * Gets the image.
+ *
+ * @return the image associate to this tab
+ */
+ public Image getImage() {
+ return this.image;
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @return the text associated to this tab
+ */
+ public String getText() {
+ return this.text;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWTabContainer.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWTabContainer.java
new file mode 100644
index 0000000..71d6815
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PWTabContainer.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * 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.preferenceWindow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+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.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.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.flatButton.FlatButton;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are a container that allows the user to select a tab.
+ */
+class PWTabContainer extends Composite {
+
+ /** The tabs. */
+ private final List<PWTab> tabs;
+
+ /** The container. */
+ private Composite container;
+
+ /** The old button container image. */
+ private Image oldButtonContainerImage;
+
+ /** The buttons. */
+ private final List<FlatButton> buttons;
+
+ /** The button container. */
+ private Composite buttonContainer;
+
+ /**
+ * Constructor.
+ *
+ * @param parent parent composite
+ * @param style style (not used)
+ * @param tabs list of tabs
+ */
+ PWTabContainer(final Composite parent, final int style, final List<PWTab> tabs) {
+ super(parent, style);
+ this.tabs = new ArrayList<PWTab>();
+ this.tabs.addAll(tabs);
+
+ this.buttons = new ArrayList<FlatButton>();
+
+ final GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.marginWidth = gridLayout.marginHeight = 0;
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
+ setLayout(gridLayout);
+
+ }
+
+ /**
+ * Build the container.
+ */
+ void build() {
+ createButtonsContainer();
+ createButtons();
+ createContentContainer();
+
+ select(PreferenceWindow.getInstance().getSelectedTab());
+ }
+
+ /**
+ * Create the buttons container.
+ */
+ private void createButtonsContainer() {
+ createContainer();
+ createButtonsContainerBackground();
+
+ }
+
+ /**
+ * Create the container.
+ */
+ private void createContainer() {
+ this.buttonContainer = new Composite(this, SWT.NONE);
+ final GridData buttonContainerGridData = new GridData(GridData.FILL, GridData.FILL, true, false, 2, 1);
+ buttonContainerGridData.heightHint = 63;
+ this.buttonContainer.setLayoutData(buttonContainerGridData);
+
+ this.buttonContainer.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+
+ final GridLayout gridLayout = new GridLayout(this.tabs.size(), false);
+ gridLayout.marginWidth = gridLayout.marginHeight = 0;
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
+ gridLayout.marginBottom = 2;
+ this.buttonContainer.setLayout(gridLayout);
+ }
+
+ /**
+ * Create the background of the container.
+ */
+ private void createButtonsContainerBackground() {
+ this.buttonContainer.addListener(SWT.Resize, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ final Rectangle rect = PWTabContainer.this.buttonContainer.getClientArea();
+ final Image image = new Image(getDisplay(), Math.max(1, rect.width), Math.max(1, rect.height));
+ final GC gc = new GC(image);
+ final Color grey = new Color(getDisplay(), 204, 204, 204);
+ gc.setForeground(grey);
+ gc.drawLine(0, rect.height - 1, rect.width, rect.height - 1);
+ grey.dispose();
+ gc.dispose();
+ PWTabContainer.this.buttonContainer.setBackgroundImage(image);
+ if (PWTabContainer.this.oldButtonContainerImage != null) {
+ PWTabContainer.this.oldButtonContainerImage.dispose();
+ }
+ PWTabContainer.this.oldButtonContainerImage = image;
+
+ }
+ });
+ SWTGraphicUtil.addDisposer(this.buttonContainer, this.oldButtonContainerImage);
+ }
+
+ /**
+ * Create the buttons.
+ */
+ private void createButtons() {
+ for (int i = 0; i < this.tabs.size(); i++) {
+ final PWTab tab = this.tabs.get(i);
+ final FlatButton button = new FlatButton(this.buttonContainer, SWT.NONE);
+ button.setText(tab.getText());
+ button.setImage(tab.getImage());
+
+ final GridData gd;
+ if (i == this.tabs.size() - 1) {
+ gd = new GridData(GridData.BEGINNING, GridData.BEGINNING, true, false);
+ } else {
+ gd = new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false);
+ }
+ if (i == 0) {
+ gd.horizontalIndent = 5;
+ }
+ gd.widthHint = 75;
+ button.setLayoutData(gd);
+
+ final int index = i;
+ button.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ select(index);
+ }
+
+ });
+
+ this.buttons.add(button);
+
+ }
+ }
+
+ /**
+ * Select a given button.
+ *
+ * @param index index of the selected button
+ */
+ void select(final int index) {
+ for (final Control c : this.container.getChildren()) {
+ c.dispose();
+ }
+
+ this.tabs.get(index).build(this.container);
+ this.container.layout();
+
+ for (int i = 0; i < this.buttons.size(); i++) {
+ this.buttons.get(i).setSelection(i == index);
+ }
+ }
+
+ /**
+ * Create the content container, ie the composite that will contain all
+ * widgets.
+ */
+ private void createContentContainer() {
+ this.container = new Composite(this, SWT.NONE);
+ final GridData tempContainer = new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1);
+ tempContainer.widthHint = 700;
+ tempContainer.heightHint = 550;
+ this.container.setLayoutData(tempContainer);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PreferenceWindow.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PreferenceWindow.java
new file mode 100644
index 0000000..12e205d
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/PreferenceWindow.java
@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * 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.preferenceWindow;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+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.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.preferenceWindow.widgets.PWWidget;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This class is a preference window.
+ */
+public class PreferenceWindow {
+
+ /** The values. */
+ private final Map<String, ValueAndAssociatedWidgets> values;
+
+ /** The tabs. */
+ private final List<PWTab> tabs;
+
+ /** The parent shell. */
+ private final Shell parentShell;
+
+ /** The returned value. */
+ private boolean returnedValue;
+
+ /** The shell. */
+ private Shell shell;
+
+ /** The instance. */
+ private static PreferenceWindow instance;
+
+ /** The container. */
+ private PWTabContainer container;
+
+ /** The selected tab. */
+ private int selectedTab;
+
+ /**
+ * Constructor.
+ *
+ * @param parent parent shell (may be null)
+ * @param values a map that contains all values that will be displayed in
+ * widgets
+ */
+ private PreferenceWindow(final Shell parent, final Map<String, Object> values) {
+ this.parentShell = parent;
+ this.values = new HashMap<String, ValueAndAssociatedWidgets>(values.size());
+
+ for (final Entry<String, Object> entry : values.entrySet()) {
+ this.values.put(entry.getKey(), new ValueAndAssociatedWidgets(entry.getValue()));
+ }
+
+ this.tabs = new ArrayList<PWTab>();
+ }
+
+ /**
+ * Create a preference window (a singleton).
+ *
+ * @param parent parent shell (may be null)
+ * @param values a map that contains all values that will be displayed in
+ * widgets
+ * @return the preference window
+ */
+ public static PreferenceWindow create(final Shell parent, final Map<String, Object> values) {
+ instance = new PreferenceWindow(parent, values);
+ return instance;
+ }
+
+ /**
+ * Create a preference window (a singleton).
+ *
+ * @param values a map that contains all values that will be displayed in
+ * widgets
+ * @return the preference window
+ */
+ public static PreferenceWindow create(final Map<String, Object> values) {
+ instance = new PreferenceWindow(null, values);
+ return instance;
+ }
+
+ /**
+ * Gets the single instance of PreferenceWindow.
+ *
+ * @return an instance of the preference window
+ */
+ public static PreferenceWindow getInstance() {
+ if (instance == null) {
+ throw new NullPointerException("The instance of PreferenceWindow has not yet been created or has been destroyed.");
+ }
+ return instance;
+ }
+
+ /**
+ * Add a tab to the preference window.
+ *
+ * @param image image associated to the tab
+ * @param text text associated to the image
+ * @return the
+ */
+ public PWTab addTab(final Image image, final String text) {
+ final PWTab tab = new PWTab(image, text);
+ this.tabs.add(tab);
+ return tab;
+ }
+
+ /**
+ * Add a widget that is linked to a given property.
+ *
+ * @param propertyKey the property
+ * @param widget the widget
+ */
+ public void addWidgetLinkedTo(final String propertyKey, final PWWidget widget) {
+ if (!this.values.containsKey(propertyKey)) {
+ this.values.put(propertyKey, new ValueAndAssociatedWidgets(null));
+ }
+ this.values.get(propertyKey).addWidget(widget);
+ }
+
+ /**
+ * Add a row group that is linked to a given property.
+ *
+ * @param propertyKey the property
+ * @param rowGroup the widget
+ */
+ public void addRowGroupLinkedTo(final String propertyKey, final PWRowGroup rowGroup) {
+ if (!this.values.containsKey(propertyKey)) {
+ this.values.put(propertyKey, new ValueAndAssociatedWidgets(null));
+ }
+ this.values.get(propertyKey).addRowGroup(rowGroup);
+ }
+
+ /**
+ * Open the preference window.
+ *
+ * @return <code>true</code> if the user pressed on the Ok button,
+ * <code>false</code> if the user pressed on the Cancel button
+ */
+ public boolean open() {
+ if (this.parentShell == null) {
+ this.shell = new Shell(SWT.SHELL_TRIM);
+ } else {
+ this.shell = new Shell(instance.parentShell, SWT.SHELL_TRIM);
+ }
+
+ this.shell.addListener(SWT.Dispose, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ instance = null; // NOSONAR
+ }
+ });
+
+ buildShell();
+ openShell();
+
+ return this.returnedValue;
+ }
+
+ /**
+ * Builds the shell.
+ */
+ private void buildShell() {
+ this.shell.setText(ResourceManager.getLabel(ResourceManager.PREFERENCES));
+ final GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.marginWidth = gridLayout.marginHeight = 0;
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
+ this.shell.setLayout(gridLayout);
+ this.container = new PWTabContainer(this.shell, SWT.NONE, this.tabs);
+ this.container.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1));
+ this.container.build();
+
+ final Label sep = new Label(this.shell, SWT.SEPARATOR | SWT.HORIZONTAL);
+ sep.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1));
+
+ buildButtons();
+
+ }
+
+ /**
+ * Builds the buttons.
+ */
+ private void buildButtons() {
+ final Button buttonOK = new Button(this.shell, SWT.PUSH);
+ buttonOK.setText(ResourceManager.getLabel(ResourceManager.OK));
+ final GridData gridDataOk = new GridData(GridData.END, GridData.END, true, false);
+ gridDataOk.widthHint = 100;
+ buttonOK.setLayoutData(gridDataOk);
+ buttonOK.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ PreferenceWindow.this.returnedValue = true;
+ PreferenceWindow.this.shell.dispose();
+ }
+
+ });
+ this.shell.setDefaultButton(buttonOK);
+
+ final Button buttonCancel = new Button(this.shell, SWT.PUSH);
+ buttonCancel.setText(ResourceManager.getLabel(ResourceManager.CANCEL));
+ final GridData gridDataCancel = new GridData(GridData.BEGINNING, GridData.END, false, false);
+ gridDataCancel.widthHint = 100;
+ buttonCancel.setLayoutData(gridDataCancel);
+ buttonCancel.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ PreferenceWindow.this.returnedValue = false;
+ PreferenceWindow.this.shell.dispose();
+ }
+
+ });
+ }
+
+ /**
+ * Open the shell.
+ */
+ private void openShell() {
+ this.shell.pack();
+ this.shell.open();
+ SWTGraphicUtil.centerShell(this.shell);
+
+ while (!this.shell.isDisposed()) {
+ if (!this.shell.getDisplay().readAndDispatch()) {
+ this.shell.getDisplay().sleep();
+ }
+ }
+
+ }
+
+ /**
+ * Fire all enablers.
+ */
+ public void fireEnablers() {
+// for (final String key : this.values.keySet()) {
+// this.values.get(key).fireValueChanged();
+ // SONAR finds it more efficient to use the iterator on the entrySet of the map, to avoid the Map.key() lookup!:
+ for (final ValueAndAssociatedWidgets mapValue : this.values.values()) {
+ mapValue.fireValueChanged();
+ }
+ }
+
+ /**
+ * Gets the selected tab.
+ *
+ * @return the selected tab
+ */
+ public int getSelectedTab() {
+ return this.selectedTab;
+ }
+
+ /**
+ * Gets the value for.
+ *
+ * @param key the key
+ * @return the value associated to the <i>key</i>
+ */
+ public Object getValueFor(final String key) {
+ if (this.values.containsKey(key)) {
+ return this.values.get(key).getValue();
+ }
+ return null;
+ }
+
+ /**
+ * Gets the values.
+ *
+ * @return the list of all values
+ */
+ public Map<String, Object> getValues() {
+ final Map<String, Object> returnedValues = new HashMap<String, Object>();
+// for (final String key : this.values.keySet()) {
+// returnedValues.put(key, this.values.get(key).getValue());
+ // SONAR finds it more efficient to use the iterator on the entrySet of the map, to avoid the Map.key() lookup!:
+ for (final Map.Entry<String, ValueAndAssociatedWidgets> entry : this.values.entrySet()) {
+ returnedValues.put(entry.getKey(), entry.getValue());
+ }
+ return returnedValues;
+ }
+
+ /**
+ * Store a value associated to the key.
+ *
+ * @param key the key
+ * @param value the value
+ */
+ public void setValue(final String key, final Object value) {
+ if (this.values.containsKey(key)) {
+ this.values.get(key).setValue(value);
+ } else {
+ this.values.put(key, new ValueAndAssociatedWidgets(value));
+ }
+
+ }
+
+ /**
+ * Set the selected tab.
+ *
+ * @param selectedTab the new selected tab
+ */
+ public void setSelectedTab(final int selectedTab) {
+ this.selectedTab = selectedTab;
+ if (this.container != null) {
+ this.container.redraw();
+ this.container.update();
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/ValueAndAssociatedWidgets.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/ValueAndAssociatedWidgets.java
new file mode 100644
index 0000000..e3345ea
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/ValueAndAssociatedWidgets.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * 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.preferenceWindow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.mihalis.opal.preferenceWindow.widgets.PWWidget;
+
+/**
+ * This POJO contains a value a list of widgets that depends on a given
+ * property.
+ */
+class ValueAndAssociatedWidgets {
+
+ /** The value. */
+ private Object value;
+
+ /** The widgets. */
+ private final List<PWWidget> widgets;
+
+ /** The row groups. */
+ private final List<PWRowGroup> rowGroups;
+
+ /**
+ * Constructor.
+ *
+ * @param value associated value
+ */
+ ValueAndAssociatedWidgets(final Object value) {
+ this.value = value;
+ this.widgets = new ArrayList<PWWidget>();
+ this.rowGroups = new ArrayList<PWRowGroup>();
+ }
+
+ /**
+ * Adds the widget.
+ *
+ * @param widget dependant widget
+ */
+ void addWidget(final PWWidget widget) {
+ this.widgets.add(widget);
+ }
+
+ /**
+ * Adds the row group.
+ *
+ * @param rowGroup dependant row or group
+ */
+ void addRowGroup(final PWRowGroup rowGroup) {
+ this.rowGroups.add(rowGroup);
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value stored in the instance
+ */
+ Object getValue() {
+ return this.value;
+ }
+
+ /**
+ * Sets the value.
+ *
+ * @param value new value stored in this instance
+ */
+ void setValue(final Object value) {
+ this.value = value;
+ fireValueChanged();
+ }
+
+ /**
+ * Fire events when the value has changed.
+ */
+ void fireValueChanged() {
+ for (final PWRowGroup rowGroup : this.rowGroups) {
+ rowGroup.enableOrDisable();
+ }
+
+ for (final PWWidget widget : this.widgets) {
+ widget.enableOrDisable();
+ }
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfEquals.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfEquals.java
new file mode 100644
index 0000000..e116981
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfEquals.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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.preferenceWindow.enabler;
+
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * This enabler is used to enable a widget if a property is equal to a given
+ * value.
+ */
+public class EnabledIfEquals extends Enabler {
+
+ /** The value. */
+ private final Object value;
+
+ /**
+ * Constructor.
+ *
+ * @param prop property to evaluate
+ * @param value condition value
+ */
+ public EnabledIfEquals(final String prop, final Object value) {
+ super(prop);
+ this.value = value;
+ }
+
+ /**
+ * Checks if is enabled.
+ *
+ * @return true, if is enabled
+ * @see org.mihalis.opal.preferenceWindow.enabler.Enabler#isEnabled()
+ */
+ @Override
+ public boolean isEnabled() {
+ final Object propValue = PreferenceWindow.getInstance().getValueFor(this.prop);
+ if (this.value == null) {
+ return propValue == null;
+ }
+ return this.value.equals(propValue);
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfNotEquals.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfNotEquals.java
new file mode 100644
index 0000000..cbf3a47
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfNotEquals.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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.preferenceWindow.enabler;
+
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * This enabler is used to enable a widget if a property is not equal to a given
+ * value.
+ */
+public class EnabledIfNotEquals extends Enabler {
+
+ /** The value. */
+ private final Object value;
+
+ /**
+ * Constructor.
+ *
+ * @param prop property to evaluate
+ * @param value condition value
+ */
+ public EnabledIfNotEquals(final String prop, final Object value) {
+ super(prop);
+ this.value = value;
+ }
+
+ /**
+ * Checks if is enabled.
+ *
+ * @return true, if is enabled
+ * @see org.mihalis.opal.preferenceWindow.enabler.Enabler#isEnabled()
+ */
+ @Override
+ public boolean isEnabled() {
+ final Object propValue = PreferenceWindow.getInstance().getValueFor(this.prop);
+ if (this.value == null) {
+ return propValue == null;
+ }
+ return !this.value.equals(propValue);
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfTrue.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfTrue.java
new file mode 100644
index 0000000..c74b37d
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/EnabledIfTrue.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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.preferenceWindow.enabler;
+
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * This enabler is used to enable a widget if a boolean property is true.
+ */
+public class EnabledIfTrue extends Enabler {
+
+ /**
+ * Constructor.
+ *
+ * @param prop boolean property
+ */
+ public EnabledIfTrue(final String prop) {
+ super(prop);
+ }
+
+ /**
+ * Checks if is enabled.
+ *
+ * @return true, if is enabled
+ * @see org.mihalis.opal.preferenceWindow.enabler.Enabler#isEnabled()
+ */
+ @Override
+ public boolean isEnabled() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(this.prop);
+
+ if (value != null && !(value instanceof Boolean)) {
+ throw new UnsupportedOperationException("Impossible to evaluate [" + this.prop + "] because it is not a Boolean !");
+ }
+
+ if (value == null) {
+ return true;
+ }
+
+ return ((Boolean) value).booleanValue();
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/Enabler.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/Enabler.java
new file mode 100644
index 0000000..5584958
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/enabler/Enabler.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * 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.preferenceWindow.enabler;
+
+import org.mihalis.opal.preferenceWindow.PWRowGroup;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+import org.mihalis.opal.preferenceWindow.widgets.PWWidget;
+
+/**
+ * This is the abstract class of all Enablers. An enabler is an object used to
+ * enable or disable a widget depending on a value of a stored property.
+ */
+public abstract class Enabler {
+
+ /** The prop. */
+ protected String prop;
+
+ /**
+ * Constructor.
+ *
+ * @param prop property linked to the enabler.
+ */
+ public Enabler(final String prop) {
+ this.prop = prop;
+ }
+
+ /**
+ * Checks if is enabled.
+ *
+ * @return the evaluation condition
+ */
+ public abstract boolean isEnabled();
+
+ /**
+ * Link a widget to the enabler.
+ *
+ * @param widget widget to link
+ */
+ public void injectWidget(final PWWidget widget) {
+ PreferenceWindow.getInstance().addWidgetLinkedTo(this.prop, widget);
+ }
+
+ /**
+ * Link a row or a group to the enabler.
+ *
+ * @param rowGroup RowGroup to link
+ */
+ public void injectRowGroup(final PWRowGroup rowGroup) {
+ PreferenceWindow.getInstance().addRowGroupLinkedTo(this.prop, rowGroup);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWButton.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWButton.java
new file mode 100644
index 0000000..acca053
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWButton.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Instances of this class are buttons.
+ */
+public class PWButton extends PWWidget {
+
+ /** The listener. */
+ private final SelectionListener listener;
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param listener selection listener
+ */
+ public PWButton(final String label, final SelectionListener listener) {
+ super(label, null, 1, true);
+ this.listener = listener;
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ final Button button = new Button(parent, SWT.PUSH);
+ addControl(button);
+ if (getLabel() == null) {
+ throw new UnsupportedOperationException("You need to set a label for a button");
+ } else {
+ button.setText(getLabel());
+ }
+ if (this.listener != null) {
+ button.addSelectionListener(this.listener);
+ }
+
+ return button;
+
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWCheckbox.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWCheckbox.java
new file mode 100644
index 0000000..f49e30c
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWCheckbox.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * Instances of this class are checkboxes.
+ */
+public class PWCheckbox extends PWWidget {
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWCheckbox(final String label, final String propertyKey) {
+ super(label, propertyKey, 1, true);
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ if (getLabel() == null) {
+ throw new UnsupportedOperationException("Please specify a label for a checkbox");
+ }
+ final Button button = new Button(parent, SWT.CHECK);
+ addControl(button);
+ button.setText(getLabel());
+ final boolean originalSelection = (Boolean) PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ button.setSelection(originalSelection);
+
+ button.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), button.getSelection());
+ }
+ });
+ return button;
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), Boolean.valueOf(false));
+ } else {
+ if (!(value instanceof Boolean)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a Boolean because it is associated to a checkbox");
+ }
+ }
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWChooser.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWChooser.java
new file mode 100644
index 0000000..a93dff6
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWChooser.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * Abstract class for chooser widgets.
+ */
+public abstract class PWChooser extends PWWidget {
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWChooser(final String label, final String propertyKey) {
+ super(label, propertyKey, 3, false);
+ setGrabExcessSpace(false);
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ final Label label = new Label(parent, SWT.NONE);
+
+ if (getLabel() == null) {
+ throw new UnsupportedOperationException("You need to set a label for a directory or a dialog chooser");
+ } else {
+ label.setText(getLabel());
+ }
+ addControl(label);
+ final GridData labelGridData = new GridData(GridData.END, GridData.BEGINNING, false, false);
+ labelGridData.horizontalIndent = getIndent();
+ label.setLayoutData(labelGridData);
+
+ final Text text = new Text(parent, SWT.BORDER | SWT.READ_ONLY);
+ addControl(text);
+ final GridData textGridData = new GridData(GridData.FILL, GridData.BEGINNING, true, false);
+ text.setLayoutData(textGridData);
+
+ final Button button = new Button(parent, SWT.PUSH);
+ addControl(button);
+ final GridData buttonGridData = new GridData(GridData.FILL, GridData.BEGINNING, false, false);
+ buttonGridData.widthHint = 150;
+ button.setText(ResourceManager.getLabel(ResourceManager.CHOOSE) + "...");
+ button.setLayoutData(buttonGridData);
+
+ setButtonAction(text, button);
+
+ return button;
+
+ }
+
+ /**
+ * Code executed when the user presses the button.
+ *
+ * @param text text box
+ * @param button associated button
+ */
+ protected abstract void setButtonAction(Text text, Button button);
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWColorChooser.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWColorChooser.java
new file mode 100644
index 0000000..fc3b0d4
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWColorChooser.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.ColorDialog;
+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.Listener;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are used to select a color.
+ */
+public class PWColorChooser extends PWWidget {
+
+ /** The color. */
+ private Color color;
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWColorChooser(final String label, final String propertyKey) {
+ super(label, propertyKey, label == null ? 1 : 2, false);
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ final RGB rgb = (RGB) PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+
+ if (rgb == null) {
+ this.color = Display.getDefault().getSystemColor(SWT.COLOR_WHITE);
+ } else {
+ this.color = new Color(Display.getDefault(), rgb);
+ }
+
+ buildLabel(parent, GridData.CENTER);
+ final Button button = new Button(parent, SWT.PUSH);
+ addControl(button);
+
+ button.addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ drawButton(button);
+ }
+ });
+
+ button.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ final ColorDialog dialog = new ColorDialog(button.getShell());
+ final RGB result = dialog.open();
+ if (result != null) {
+ SWTGraphicUtil.safeDispose(PWColorChooser.this.color);
+ PWColorChooser.this.color = new Color(button.getDisplay(), result);
+ drawButton(button);
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), result);
+ }
+ }
+ });
+ return button;
+ }
+
+ /**
+ * Draw button.
+ *
+ * @param button button on which we draw the rectangle
+ */
+ protected void drawButton(final Button button) {
+ final int height = (int) button.getFont().getFontData()[0].height;
+ final int width = button.getBounds().width - 16;
+
+ final Image newImage = new Image(button.getDisplay(), Math.max(1, width), Math.max(1, height));
+
+ final GC gc = new GC(newImage);
+ gc.setBackground(PWColorChooser.this.color);
+ gc.fillRectangle(0, 0, width, height);
+
+ gc.setForeground(button.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ gc.drawRectangle(0, 0, width - 1, height - 1);
+
+ gc.dispose();
+
+ button.setImage(newImage);
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), null);
+ } else {
+ if (!(value instanceof RGB)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a RGB because it is associated to a color chooser");
+ }
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWCombo.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWCombo.java
new file mode 100644
index 0000000..d2fdbc3
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWCombo.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * Instances of this class are Combo.
+ */
+public class PWCombo extends PWWidget {
+
+ /** The data. */
+ private final List<Object> data;
+
+ /** The editable. */
+ private final boolean editable;
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ * @param values the values
+ */
+ public PWCombo(final String label, final String propertyKey, final Object... values) {
+ this(label, propertyKey, false, values);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ * @param editable the editable
+ * @param values the values
+ */
+ public PWCombo(final String label, final String propertyKey, final boolean editable, final Object... values) {
+ super(label, propertyKey, label == null ? 1 : 2, false);
+ this.data = new ArrayList<Object>(Arrays.asList(values));
+ this.editable = editable;
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ buildLabel(parent, GridData.CENTER);
+
+ final Combo combo = new Combo(parent, SWT.BORDER | (this.editable ? SWT.NONE : SWT.READ_ONLY));
+ addControl(combo);
+
+ for (int i = 0; i < this.data.size(); i++) {
+ final Object datum = this.data.get(i);
+ combo.add(datum.toString());
+ if (datum.equals(PreferenceWindow.getInstance().getValueFor(getPropertyKey()))) {
+ combo.select(i);
+ }
+ }
+
+ combo.addListener(SWT.Modify, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), PWCombo.this.data.get(combo.getSelectionIndex()));
+ }
+ });
+
+ return combo;
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), null);
+ } else {
+ if (this.editable && !(value instanceof String)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a String because it is associated to an editable combo");
+ }
+
+ if (!this.data.isEmpty()) {
+ if (!value.getClass().equals(this.data.get(0).getClass())) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a " + this.data.get(0).getClass() + " because it is associated to a combo");
+ }
+ }
+
+ }
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWDirectoryChooser.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWDirectoryChooser.java
new file mode 100644
index 0000000..624d6d3
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWDirectoryChooser.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * Instances of this class are used to select a directory.
+ */
+public class PWDirectoryChooser extends PWChooser {
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWDirectoryChooser(final String label, final String propertyKey) {
+ super(label, propertyKey);
+ }
+
+ /**
+ * Sets the button action.
+ *
+ * @param text the text
+ * @param button the button
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWChooser#setButtonAction(org.eclipse.swt.widgets.Text,
+ * org.eclipse.swt.widgets.Button)
+ */
+ @Override
+ protected void setButtonAction(final Text text, final Button button) {
+
+ final String originalDirectory = (String) PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ text.setText(originalDirectory);
+
+ button.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ final DirectoryDialog dialog = new DirectoryDialog(text.getShell());
+ dialog.setMessage(ResourceManager.getLabel(ResourceManager.CHOOSE_DIRECTORY));
+ final String result = dialog.open();
+ if (result != null) {
+ text.setText(result);
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), result);
+ }
+
+ }
+ });
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), "");
+ } else {
+ if (!(value instanceof String)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a String because it is associated to a directory chooser");
+ }
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFileChooser.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFileChooser.java
new file mode 100644
index 0000000..b3ffd50
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFileChooser.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * Instances of this class are used to select a file.
+ */
+public class PWFileChooser extends PWChooser {
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWFileChooser(final String label, final String propertyKey) {
+ super(label, propertyKey);
+ }
+
+ /**
+ * Sets the button action.
+ *
+ * @param text the text
+ * @param button the button
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWChooser#setButtonAction(org.eclipse.swt.widgets.Text,
+ * org.eclipse.swt.widgets.Button)
+ */
+ @Override
+ protected void setButtonAction(final Text text, final Button button) {
+ final String originalFile = (String) PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ text.setText(originalFile);
+
+ button.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ final FileDialog dialog = new FileDialog(text.getShell(), SWT.OPEN);
+ final String result = dialog.open();
+ if (result != null) {
+ text.setText(result);
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), result);
+ }
+
+ }
+ });
+
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), "");
+ } else {
+ if (!(value instanceof String)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a String because it is associated to a file chooser");
+ }
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFloatText.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFloatText.java
new file mode 100644
index 0000000..6eb0f94
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFloatText.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.events.VerifyListener;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+import org.mihalis.opal.utils.StringUtil;
+
+/**
+ * Instances of this class are text box to type floats.
+ */
+public class PWFloatText extends PWText {
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWFloatText(final String label, final String propertyKey) {
+ super(label, propertyKey);
+ }
+
+ /**
+ * Adds the verify listeners.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#addVerifyListeners()
+ */
+ @Override
+ public void addVerifyListeners() {
+ 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.character != '.' && e.character != ',') {
+ e.doit = false;
+ return;
+ }
+
+ e.doit = verifyEntry(e.text, e.keyCode);
+
+ }
+ });
+
+ }
+
+ /**
+ * Check if an entry is a float.
+ *
+ * @param entry text typed by the user
+ * @param keyCode key code
+ * @return true if the user typed a float value, false otherwise
+ */
+ private boolean verifyEntry(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 {
+ Double.parseDouble(work.replace(',', '.'));
+ } catch (final NumberFormatException nfe) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), new Float(0));
+ } else {
+ if (!(value instanceof Float)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a Float because it is associated to a float text widget");
+ }
+ }
+ }
+
+ /**
+ * Convert value.
+ *
+ * @return the object
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#convertValue()
+ */
+ @Override
+ public Object convertValue() {
+ return Float.parseFloat(this.text.getText());
+ }
+
+ /**
+ * Gets the style.
+ *
+ * @return the style
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#getStyle()
+ */
+ @Override
+ public int getStyle() {
+ return SWT.NONE;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFontChooser.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFontChooser.java
new file mode 100644
index 0000000..b16256a
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWFontChooser.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.FontDialog;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * Instances of this class are used to select a font.
+ */
+public class PWFontChooser extends PWChooser {
+
+ /** The font data. */
+ private FontData fontData;
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWFontChooser(final String label, final String propertyKey) {
+ super(label, propertyKey);
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), null);
+ } else {
+ if (!(value instanceof FontData)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a FontData because it is associated to a font chooser");
+ }
+ }
+ }
+
+ /**
+ * Sets the button action.
+ *
+ * @param text the text
+ * @param button the button
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWChooser#setButtonAction(org.eclipse.swt.widgets.Text,
+ * org.eclipse.swt.widgets.Button)
+ */
+ @Override
+ protected void setButtonAction(final Text text, final Button button) {
+ this.fontData = (FontData) PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+
+ button.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ final FontDialog dialog = new FontDialog(text.getShell());
+ final FontData result = dialog.open();
+ if (result != null && result.getName() != null && !"".equals(result.getName().trim())) {
+ PWFontChooser.this.fontData = result;
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), result);
+ text.setText(buildFontInformation());
+ }
+
+ }
+ });
+
+ }
+
+ /**
+ * Builds the font information.
+ *
+ * @return a string that contains data about the choosen font
+ */
+ protected String buildFontInformation() {
+ final StringBuilder sb = new StringBuilder();
+ if (this.fontData != null) {
+ sb.append(this.fontData.getName()).append(",").append(this.fontData.getHeight()).append(" pt");
+ if ((this.fontData.getStyle() & SWT.BOLD) == SWT.BOLD) {
+ sb.append(", ").append(ResourceManager.getLabel(ResourceManager.BOLD));
+ }
+ if ((this.fontData.getStyle() & SWT.ITALIC) == SWT.ITALIC) {
+ sb.append(", ").append(ResourceManager.getLabel(ResourceManager.ITALIC));
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWIntegerText.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWIntegerText.java
new file mode 100644
index 0000000..c350e22
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWIntegerText.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * Instances of this class are text box to type Integers.
+ */
+public class PWIntegerText extends PWText {
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWIntegerText(final String label, final String propertyKey) {
+ super(label, propertyKey);
+ }
+
+ /**
+ * Adds the verify listeners.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#addVerifyListeners()
+ */
+ @Override
+ public void addVerifyListeners() {
+ this.text.addListener(SWT.Verify, new Listener() {
+ @Override
+ public void handleEvent(final Event e) {
+ final String string = e.text;
+ final char[] chars = new char[string.length()];
+ string.getChars(0, chars.length, chars, 0);
+ for (int i = 0; i < chars.length; i++) {
+ if (!('0' <= chars[i] && chars[i] <= '9') && e.keyCode != SWT.BS && e.keyCode != SWT.DEL) {
+ e.doit = false;
+ return;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), Integer.valueOf(0));
+ } else {
+ if (!(value instanceof Integer)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be an Integer because it is associated to a integer text widget");
+ }
+ }
+ }
+
+ /**
+ * Convert value.
+ *
+ * @return the object
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#convertValue()
+ */
+ @Override
+ public Object convertValue() {
+ return Integer.parseInt(this.text.getText());
+ }
+
+ /**
+ * Gets the style.
+ *
+ * @return the style
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#getStyle()
+ */
+ @Override
+ public int getStyle() {
+ return SWT.NONE;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWLabel.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWLabel.java
new file mode 100644
index 0000000..353ba75
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWLabel.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are labels, that could contain some HTML tags
+ * (B,I,U).
+ */
+public class PWLabel extends PWWidget {
+
+ /** The label widget. */
+ private StyledText labelWidget;
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ */
+ public PWLabel(final String label) {
+ super(label, null, 1, true);
+ setAlignment(GridData.FILL);
+ setGrabExcessSpace(true);
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ if (getLabel() == null) {
+ throw new UnsupportedOperationException("You need to set a description for a PWLabel object");
+ }
+ this.labelWidget = new StyledText(parent, SWT.WRAP | SWT.READ_ONLY);
+ this.labelWidget.setEnabled(false);
+ this.labelWidget.setBackground(parent.getBackground());
+ this.labelWidget.setText(getLabel());
+ SWTGraphicUtil.applyHTMLFormating(this.labelWidget);
+ return this.labelWidget;
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ }
+
+ /**
+ * Enable or disable.
+ *
+ * @return true, if successful
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#enableOrDisable()
+ */
+ @Override
+ public boolean enableOrDisable() {
+ if (this.enabler == null) {
+ return true;
+ }
+
+ final boolean enabled = this.enabler.isEnabled();
+ if (!this.labelWidget.isDisposed()) {
+ if (enabled) {
+ this.labelWidget.setForeground(this.labelWidget.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ } else {
+ this.labelWidget.setForeground(this.labelWidget.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
+ }
+ }
+ return enabled;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWPasswordText.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWPasswordText.java
new file mode 100644
index 0000000..0e29918
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWPasswordText.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * Instances of this class are text box to type password.
+ */
+public class PWPasswordText extends PWText {
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWPasswordText(final String label, final String propertyKey) {
+ super(label, propertyKey);
+ }
+
+ /**
+ * Adds the verify listeners.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#addVerifyListeners()
+ */
+ @Override
+ public void addVerifyListeners() {
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), "");
+ } else {
+ if (!(value instanceof String)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a String because it is associated to a password text box");
+ }
+ }
+
+ }
+
+ /**
+ * Convert value.
+ *
+ * @return the object
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#convertValue()
+ */
+ @Override
+ public Object convertValue() {
+ return this.text.getText();
+ }
+
+ /**
+ * Gets the style.
+ *
+ * @return the style
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#getStyle()
+ */
+ @Override
+ public int getStyle() {
+ return SWT.PASSWORD;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWRadio.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWRadio.java
new file mode 100644
index 0000000..f364f26
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWRadio.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+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.Listener;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * Instances of this class are a group of radio buttons.
+ */
+public class PWRadio extends PWWidget {
+
+ /** The data. */
+ private final List<Object> data;
+
+ /** The buttons. */
+ private final List<Button> buttons;
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param prop the prop
+ * @param values the values
+ */
+ public PWRadio(final String label, final String prop, final Object... values) {
+ super(null, prop, label == null ? 1 : 2, false);
+ this.data = new ArrayList<Object>(Arrays.asList(values));
+ this.buttons = new ArrayList<Button>();
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ buildLabel(parent, GridData.BEGINNING);
+
+ final Composite composite = new Composite(parent, SWT.NONE);
+ final GridLayout gridLayout = new GridLayout();
+ gridLayout.marginHeight = gridLayout.marginWidth = 0;
+ composite.setLayout(gridLayout);
+
+ for (final Object datum : this.data) {
+ final Button button = new Button(composite, SWT.RADIO);
+ addControl(button);
+ button.setText(datum.toString());
+ button.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ button.setSelection(datum.equals(PreferenceWindow.getInstance().getValueFor(getPropertyKey())));
+ button.setData(datum);
+ button.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ if (button.getSelection()) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), button.getData());
+ }
+ }
+ });
+
+ this.buttons.add(button);
+ }
+ return composite;
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), null);
+ } else {
+ if (!this.data.isEmpty()) {
+ if (!value.getClass().equals(this.data.get(0).getClass())) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a " + this.data.get(0).getClass() + " because it is associated to a combo");
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWScale.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWScale.java
new file mode 100644
index 0000000..ff87326
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWScale.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Scale;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * Instances of this class are scales.
+ */
+public class PWScale extends PWWidget {
+
+ /** The max. */
+ private final int max;
+
+ /** The min. */
+ private final int min;
+
+ /** The increment. */
+ private final int increment;
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ * @param min minimum value
+ * @param max maximum value
+ * @param increment increment value
+ */
+ public PWScale(final String label, final String propertyKey, final int min, final int max, final int increment) {
+ super(label, propertyKey, label == null ? 1 : 2, false);
+ this.min = min;
+ this.max = max;
+ this.increment = increment;
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ buildLabel(parent, GridData.CENTER);
+ final Scale scale = new Scale(parent, SWT.HORIZONTAL);
+ addControl(scale);
+ scale.setIncrement(this.increment);
+ scale.setMinimum(this.min);
+ scale.setMaximum(this.max);
+ final Integer originalValue = (Integer) PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ scale.setSelection(originalValue.intValue());
+
+ scale.addListener(SWT.Modify, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), Integer.valueOf(scale.getSelection()));
+ }
+ });
+
+ return scale;
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), Integer.valueOf(this.min));
+ } else {
+ if (!(value instanceof Integer)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be an Integer because it is associated to a iscale");
+ }
+
+ final int valueAsInt = ((Integer) value).intValue();
+ if (valueAsInt < this.min || valueAsInt > this.max) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' is out of range (value is " + valueAsInt + ", range is " + this.min + "-" + this.max + ")");
+ }
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWSeparator.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWSeparator.java
new file mode 100644
index 0000000..f323688
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWSeparator.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.mihalis.opal.titledSeparator.TitledSeparator;
+
+/**
+ * Instances of this class are separators.
+ */
+public class PWSeparator extends PWWidget {
+
+ /** The image. */
+ private final Image image;
+
+ /**
+ * Constructor.
+ */
+ public PWSeparator() {
+ this(null, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ */
+ public PWSeparator(final String label) {
+ this(label, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param image associated image
+ */
+ public PWSeparator(final String label, final Image image) {
+ super(label, null, 1, true);
+ this.image = image;
+ setAlignment(GridData.FILL);
+ setGrabExcessSpace(true);
+ setHeight(20);
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ final TitledSeparator sep = new TitledSeparator(parent, SWT.NONE);
+ addControl(sep);
+ sep.setText(getLabel());
+ sep.setImage(this.image);
+ return sep;
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWSpinner.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWSpinner.java
new file mode 100644
index 0000000..7d51987
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWSpinner.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Spinner;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * Instances of this class are spinners.
+ */
+public class PWSpinner extends PWWidget {
+
+ /** The max. */
+ private final int max;
+
+ /** The min. */
+ private final int min;
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ * @param min minimum value
+ * @param max maximum value
+ */
+ public PWSpinner(final String label, final String propertyKey, final int min, final int max) {
+ super(label, propertyKey, label == null ? 1 : 2, false);
+ this.min = min;
+ this.max = max;
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ buildLabel(parent, GridData.CENTER);
+ final Spinner spinner = new Spinner(parent, SWT.HORIZONTAL | SWT.BORDER);
+ addControl(spinner);
+ spinner.setMinimum(this.min);
+ spinner.setMaximum(this.max);
+ final Integer originalValue = (Integer) PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ spinner.setSelection(originalValue.intValue());
+
+ spinner.addListener(SWT.Modify, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), Integer.valueOf(spinner.getSelection()));
+ }
+ });
+
+ return spinner;
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), Integer.valueOf(this.min));
+ } else {
+ if (!(value instanceof Integer)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be an Integer because it is associated to a spinner");
+ }
+
+ final int valueAsInt = ((Integer) value).intValue();
+ if (valueAsInt < this.min || valueAsInt > this.max) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' is out of range (value is " + valueAsInt + ", range is " + this.min + "-" + this.max + ")");
+ }
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWStringText.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWStringText.java
new file mode 100644
index 0000000..402dd51
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWStringText.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * Instances of this class are text box to type Strings.
+ */
+public class PWStringText extends PWText {
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWStringText(final String label, final String propertyKey) {
+ super(label, propertyKey);
+ }
+
+ /**
+ * Adds the verify listeners.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#addVerifyListeners()
+ */
+ @Override
+ public void addVerifyListeners() {
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), "");
+ } else {
+ if (!(value instanceof String)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a String because it is associated to a stringtext");
+ }
+ }
+ }
+
+ /**
+ * Convert value.
+ *
+ * @return the object
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#convertValue()
+ */
+ @Override
+ public Object convertValue() {
+ return this.text.getText();
+ }
+
+ /**
+ * Gets the style.
+ *
+ * @return the style
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#getStyle()
+ */
+ @Override
+ public int getStyle() {
+ return SWT.NONE;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWText.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWText.java
new file mode 100644
index 0000000..90c68ef
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWText.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * This is the abstract class for all text widgets (except textarea).
+ */
+public abstract class PWText extends PWWidget {
+
+ /** The text. */
+ protected Text text;
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated property key
+ */
+ public PWText(final String label, final String propertyKey) {
+ super(label, propertyKey, label == null ? 1 : 2, false);
+ setGrabExcessSpace(true);
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ buildLabel(parent, GridData.CENTER);
+ this.text = new Text(parent, SWT.BORDER | getStyle());
+ addControl(this.text);
+ addVerifyListeners();
+ this.text.setText(PreferenceWindow.getInstance().getValueFor(getPropertyKey()).toString());
+ this.text.addListener(SWT.Modify, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), convertValue());
+ }
+ });
+ return this.text;
+ }
+
+ /**
+ * Add the verify listeners.
+ */
+ public abstract void addVerifyListeners();
+
+ /**
+ * Convert value.
+ *
+ * @return the value of the data typed by the user in the correct format
+ */
+ public abstract Object convertValue();
+
+ /**
+ * Gets the style.
+ *
+ * @return the style (SWT.NONE or SWT.PASSWORD)
+ */
+ public abstract int getStyle();
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWTextarea.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWTextarea.java
new file mode 100644
index 0000000..a209563
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWTextarea.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+
+/**
+ * Instances of this class are text areas.
+ */
+public class PWTextarea extends PWWidget {
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWTextarea(final String label, final String propertyKey) {
+ super(label, propertyKey, label == null ? 1 : 2, false);
+ setGrabExcessSpace(true);
+ setHeight(50);
+ setWidth(350);
+ }
+
+ /**
+ * Builds the.
+ *
+ * @param parent the parent
+ * @return the control
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#build(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Control build(final Composite parent) {
+ buildLabel(parent, GridData.BEGINNING);
+
+ final Text text = new Text(parent, SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ addControl(text);
+ text.setText(PreferenceWindow.getInstance().getValueFor(getPropertyKey()).toString());
+ text.addListener(SWT.FocusOut, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), text.getText());
+ }
+ });
+
+ return text;
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), "");
+ } else {
+ if (!(value instanceof String)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a String because it is associated to a textarea");
+ }
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWURLText.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWURLText.java
new file mode 100644
index 0000000..37dff7c
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWURLText.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.opalDialog.Dialog;
+import org.mihalis.opal.preferenceWindow.PreferenceWindow;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * Instances of this class are text box used to type URL.
+ */
+public class PWURLText extends PWText {
+
+ /**
+ * Constructor.
+ *
+ * @param label associated label
+ * @param propertyKey associated key
+ */
+ public PWURLText(final String label, final String propertyKey) {
+ super(label, propertyKey);
+ setWidth(200);
+ }
+
+ /**
+ * Adds the verify listeners.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#addVerifyListeners()
+ */
+ @Override
+ public void addVerifyListeners() {
+ this.text.addListener(SWT.FocusOut, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ try {
+ new URL(PWURLText.this.text.getText()); // NOSONAR
+ } catch (final MalformedURLException e) {
+ Dialog.error(ResourceManager.getLabel(ResourceManager.APPLICATION_ERROR), ResourceManager.getLabel(ResourceManager.VALID_URL));
+ event.doit = false;
+ PWURLText.this.text.forceFocus();
+ }
+
+ }
+ });
+
+ }
+
+ /**
+ * Check.
+ *
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWWidget#check()
+ */
+ @Override
+ public void check() {
+ final Object value = PreferenceWindow.getInstance().getValueFor(getPropertyKey());
+ if (value == null) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), "");
+ } else {
+ if (!(value instanceof String)) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has to be a String because it is associated to a URL text box");
+ }
+
+ final String str = (String) value;
+ if (str.equals("")) {
+ PreferenceWindow.getInstance().setValue(getPropertyKey(), "");
+ return;
+ }
+
+ try {
+ new URL(str); // NOSONAR
+ } catch (final MalformedURLException e) {
+ throw new UnsupportedOperationException("The property '" + getPropertyKey() + "' has a value (" + value + ") that is not an URL");
+ }
+ }
+ }
+
+ /**
+ * Convert value.
+ *
+ * @return the object
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#convertValue()
+ */
+ @Override
+ public Object convertValue() {
+ return this.text.getText();
+ }
+
+ /**
+ * Gets the style.
+ *
+ * @return the style
+ * @see org.mihalis.opal.preferenceWindow.widgets.PWText#getStyle()
+ */
+ @Override
+ public int getStyle() {
+ return SWT.NONE;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWWidget.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWWidget.java
new file mode 100644
index 0000000..2e11b7c
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/preferenceWindow/widgets/PWWidget.java
@@ -0,0 +1,317 @@
+/*******************************************************************************
+ * 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.preferenceWindow.widgets;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.mihalis.opal.preferenceWindow.enabler.Enabler;
+
+/**
+ * This class is the root class for all widgets that take part of a preference
+ * window.
+ */
+public abstract class PWWidget {
+
+ /** The property key. */
+ private final String propertyKey;
+
+ /** The label. */
+ private final String label;
+
+ /** The enabler. */
+ protected Enabler enabler;
+
+ /** The controls. */
+ private final List<Control> controls;
+
+ /** The alignment. */
+ private int alignment = GridData.BEGINNING;
+
+ /** The indent. */
+ private int indent = 0;
+
+ /** The width. */
+ private int width = 100;
+
+ /** The height. */
+ private int height = -1;
+
+ /** The number of columns. */
+ protected int numberOfColumns = 1;
+
+ /** The grab excess space. */
+ private boolean grabExcessSpace = false;
+
+ /** The single widget. */
+ private boolean singleWidget = false;
+
+ /**
+ * Constructor.
+ *
+ * @param label label associated to the widget
+ * @param propertyKey property key binded to the widget
+ * @param numberOfColumns number of columns taken by the widget
+ * @param singleWidget if true, the widget is supposed to be "alone" (used
+ * for placement)
+ */
+ protected PWWidget(final String label, final String propertyKey, final int numberOfColumns, final boolean singleWidget) {
+ this.label = label;
+ this.propertyKey = propertyKey;
+ this.numberOfColumns = numberOfColumns;
+ this.singleWidget = singleWidget;
+ this.controls = new ArrayList<Control>();
+ }
+
+ /**
+ * Build the widget.
+ *
+ * @param parent parent composite
+ * @return the created control
+ */
+ protected abstract Control build(Composite parent);
+
+ /**
+ * Build the label associated to the widget.
+ *
+ * @param parent parent composite
+ * @param verticalAlignment vertical alignment
+ */
+ protected void buildLabel(final Composite parent, final int verticalAlignment) {
+ if (getLabel() != null) {
+ final Label label = new Label(parent, SWT.NONE);
+ label.setText(getLabel());
+ final GridData labelGridData = new GridData(GridData.END, verticalAlignment, false, false);
+ labelGridData.horizontalIndent = getIndent();
+ label.setLayoutData(labelGridData);
+ addControl(label);
+ }
+ }
+
+ /**
+ * Check if the property can be binded to the widget.
+ *
+ * @throws UnsupportedOperationException if the property could not be binded
+ * to the widget
+ */
+ protected abstract void check();
+
+ /**
+ * Check if the property can be binded to the widget, then build the widget.
+ *
+ * @param parent parent composite
+ * @return the created control
+ */
+ public Control checkAndBuild(final Composite parent) {
+ check();
+ return build(parent);
+ }
+
+ /**
+ * Enable or disable the widget, depending on the associated enabler.
+ *
+ * @return true, if successful
+ */
+ public boolean enableOrDisable() {
+ if (this.enabler == null) {
+ return true;
+ }
+
+ final boolean enabled = this.enabler.isEnabled();
+ for (final Control c : this.controls) {
+ if (!c.isDisposed()) {
+ c.setEnabled(enabled);
+ }
+ }
+ return enabled;
+ }
+
+ // ------------------------------- getters & setters
+
+ /**
+ * Gets the alignment.
+ *
+ * @return the alignment (GridData.BEGINNING, GridData.CENTER, GridData.END,
+ * GridData.FILL)
+ */
+ public int getAlignment() {
+ return this.alignment;
+ }
+
+ /**
+ * Gets the controls.
+ *
+ * @return the list of controls contained in the widget
+ */
+ public List<Control> getControls() {
+ return this.controls;
+ }
+
+ /**
+ * Checks if is grab excess space.
+ *
+ * @return <code>true</code> if the widget should grab the excess space
+ */
+ public boolean isGrabExcessSpace() {
+ return this.grabExcessSpace;
+ }
+
+ /**
+ * Gets the height.
+ *
+ * @return the height of the widget
+ */
+ public int getHeight() {
+ return this.height;
+ }
+
+ /**
+ * Gets the indent.
+ *
+ * @return the indentation space of the widget
+ */
+ public int getIndent() {
+ return this.indent;
+ }
+
+ /**
+ * Gets the label.
+ *
+ * @return the label associated to the widget (may be <code>null</code>)
+ */
+ public String getLabel() {
+ return this.label;
+ }
+
+ /**
+ * Gets the number of columns.
+ *
+ * @return the number of columns associated to the widget
+ */
+ public int getNumberOfColumns() {
+ return this.numberOfColumns;
+ }
+
+ /**
+ * Gets the property key.
+ *
+ * @return the propertyKey associated to the widget
+ */
+ String getPropertyKey() {
+ return this.propertyKey;
+ }
+
+ /**
+ * Gets the width.
+ *
+ * @return the width of the widget
+ */
+ public int getWidth() {
+ return this.width;
+ }
+
+ /**
+ * Checks if is single widget.
+ *
+ * @return <code>true</code> if the widget is "alone"
+ */
+ public boolean isSingleWidget() {
+ return this.singleWidget;
+ }
+
+ /**
+ * Adds a control to the list of control contained in the widget.
+ *
+ * @param control control to add
+ */
+ protected void addControl(final Control control) {
+ this.controls.add(control);
+ }
+
+ /**
+ * Sets the alignment.
+ *
+ * @param alignment the alignment to set (GridData.BEGINNING,
+ * GridData.CENTER, GridData.END, GridData.FILL)
+ * @return the widget
+ */
+ public PWWidget setAlignment(final int alignment) {
+ if (alignment != GridData.BEGINNING && alignment != GridData.CENTER && alignment != GridData.END && alignment != GridData.FILL) {
+ throw new UnsupportedOperationException("Value should be one of the following :GridData.BEGINNING, GridData.CENTER, GridData.END, GridData.FILL");
+ }
+ this.alignment = alignment;
+ return this;
+ }
+
+ /**
+ * Sets the enabler.
+ *
+ * @param enabler the enabler to set
+ * @return the widget
+ */
+ public PWWidget setEnabler(final Enabler enabler) {
+ this.enabler = enabler;
+ this.enabler.injectWidget(this);
+ return this;
+ }
+
+ /**
+ * Sets the grab excess space.
+ *
+ * @param grabExcessSpace true if you want the widget to grab the excess
+ * space
+ * @return the widget
+ */
+ public PWWidget setGrabExcessSpace(final boolean grabExcessSpace) {
+ this.grabExcessSpace = grabExcessSpace;
+ return this;
+ }
+
+ /**
+ * Sets the height.
+ *
+ * @param height the height to set
+ * @return the widget
+ */
+ public PWWidget setHeight(final int height) {
+ this.height = height;
+ return this;
+
+ }
+
+ /**
+ * Sets the indent.
+ *
+ * @param indent the indentation space to set
+ * @return the widget
+ */
+ public PWWidget setIndent(final int indent) {
+ this.indent = indent;
+ return this;
+ }
+
+ /**
+ * Sets the width.
+ *
+ * @param width the width to set
+ * @return the widget
+ */
+ public PWWidget setWidth(final int width) {
+ this.width = width;
+ return this;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/BaseFocusControlListener.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/BaseFocusControlListener.java
new file mode 100644
index 0000000..259007c
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/BaseFocusControlListener.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * 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
+ *
+ * Contributor:
+ * Laurent CARON (laurent.caron@gmail.com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.promptSupport;
+
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.widgets.Control;
+import org.mihalis.opal.promptSupport.PromptSupport.FocusBehavior;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Abstract class that contains code for the FocusLost, FocusGained and
+ * ControlResized events.
+ *
+ * @see BaseFocusControlEvent
+ */
+abstract class BaseFocusControlListener implements FocusListener, ControlListener {
+
+ /** The control. */
+ protected Control control;
+
+ /** The first draw. */
+ private boolean firstDraw;
+
+ /** The initial font. */
+ private Font initialFont;
+
+ /** The initial background color. */
+ private Color initialBackgroundColor;
+
+ /** The initial foreground color. */
+ private Color initialForegroundColor;
+
+ /** The Constant EMPTY_STRING. */
+ protected static final String EMPTY_STRING = "";
+
+ /**
+ * Constructor.
+ *
+ * @param control control on which this listener will be attached
+ */
+ BaseFocusControlListener(final Control control) {
+ this.control = control;
+ this.firstDraw = true;
+ }
+
+ /**
+ * Focus gained.
+ *
+ * @param e the e
+ * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
+ */
+ @Override
+ public void focusGained(final FocusEvent e) {
+ if (isFilled()) {
+ // Widget not empty
+ return;
+ }
+
+ applyInitialLook();
+ if (PromptSupport.getFocusBehavior(this.control) == FocusBehavior.HIDE_PROMPT) {
+ hidePrompt();
+ } else {
+ highLightPrompt();
+ }
+ }
+
+ /**
+ * Apply the initial look of the widget.
+ */
+ private void applyInitialLook() {
+ this.control.setFont(this.initialFont);
+ this.control.setBackground(this.initialBackgroundColor);
+ this.control.setForeground(this.initialForegroundColor);
+ }
+
+ /**
+ * Code when the focus behiaviour is "Hide".
+ */
+ protected abstract void hidePrompt();
+
+ /**
+ * Code when the focus behiaviour is "Highlight".
+ */
+ protected abstract void highLightPrompt();
+
+ /**
+ * Focus lost.
+ *
+ * @param e the e
+ * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
+ */
+ @Override
+ public void focusLost(final FocusEvent e) {
+ if (isFilled()) {
+ return;
+ }
+
+ storeInitialLook();
+ applyForegroundColor();
+ applyBackgroundColor();
+ applyFontStyle();
+ fillPromptText();
+ }
+
+ /**
+ * Checks if is filled.
+ *
+ * @return <code>true</code> if the widget is filled, <code>false</code>
+ * otherwise
+ */
+ protected abstract boolean isFilled();
+
+ /**
+ * Apply the foreground color for the prompt.
+ */
+ private void applyForegroundColor() {
+ this.control.setForeground(PromptSupport.getForeground(this.control));
+ }
+
+ /**
+ * Apply the background color for the prompt.
+ */
+ private void applyBackgroundColor() {
+ this.control.setBackground(PromptSupport.getBackground(this.control));
+ }
+
+ /**
+ * Apply the font style to the prompt.
+ */
+ private void applyFontStyle() {
+ final Font font = SWTGraphicUtil.buildFontFrom(this.control, PromptSupport.getFontStyle(this.control));
+ this.control.setFont(font);
+ SWTGraphicUtil.addDisposer(this.control, font);
+ }
+
+ /**
+ * Fill the prompt text.
+ */
+ protected abstract void fillPromptText();
+
+ /**
+ * Control moved.
+ *
+ * @param e the e
+ * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent)
+ */
+ @Override
+ public void controlMoved(final ControlEvent e) {
+ }
+
+ /**
+ * Control resized.
+ *
+ * @param e the e
+ * @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent)
+ */
+ @Override
+ public void controlResized(final ControlEvent e) {
+ if (this.firstDraw) {
+ storeInitialLook();
+ this.firstDraw = true;
+ focusLost(null);
+ }
+ }
+
+ /**
+ * Store the initial look of the widget.
+ */
+ private void storeInitialLook() {
+ this.initialFont = this.control.getFont();
+ this.initialBackgroundColor = this.control.getBackground();
+ this.initialForegroundColor = this.control.getForeground();
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/CComboFocusControlListener.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/CComboFocusControlListener.java
new file mode 100644
index 0000000..815600e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/CComboFocusControlListener.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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.promptSupport;
+
+import org.eclipse.swt.custom.CCombo;
+
+/**
+ * Focus/Control listener for a CCombo widget.
+ *
+ * @see CComboFocusControlEvent
+ */
+class CComboFocusControlListener extends BaseFocusControlListener {
+
+ /**
+ * Constructor.
+ *
+ * @param control control on which this listener will be attached
+ */
+ public CComboFocusControlListener(final CCombo control) {
+ super(control);
+ }
+
+ /**
+ * Hide prompt.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#hidePrompt()
+ */
+ @Override
+ protected void hidePrompt() {
+ ((CCombo) this.control).setText(EMPTY_STRING);
+ }
+
+ /**
+ * High light prompt.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#highLightPrompt()
+ */
+ @Override
+ protected void highLightPrompt() {
+ }
+
+ /**
+ * Fill prompt text.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#fillPromptText()
+ */
+ @Override
+ protected void fillPromptText() {
+ final String promptText = PromptSupport.getPrompt(this.control);
+ if (promptText != null) {
+ ((CCombo) this.control).setText(promptText);
+ }
+ }
+
+ /**
+ * Checks if is filled.
+ *
+ * @return true, if is filled
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#isFilled()
+ */
+ @Override
+ protected boolean isFilled() {
+ final String promptText = PromptSupport.getPrompt(this.control);
+ if (promptText != null && promptText.equals(((CCombo) this.control).getText().trim())) {
+ return false;
+ }
+ return !EMPTY_STRING.equals(((CCombo) this.control).getText().trim());
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/ComboFocusControlListener.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/ComboFocusControlListener.java
new file mode 100644
index 0000000..0a629ea
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/ComboFocusControlListener.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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.promptSupport;
+
+import org.eclipse.swt.widgets.Combo;
+
+/**
+ * Focus/Control listener for a Combo widget.
+ *
+ * @see ComboFocusControlEvent
+ */
+class ComboFocusControlListener extends BaseFocusControlListener {
+
+ /**
+ * Constructor.
+ *
+ * @param control control on which this listener will be attached
+ */
+ public ComboFocusControlListener(final Combo control) {
+ super(control);
+ }
+
+ /**
+ * Hide prompt.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#hidePrompt()
+ */
+ @Override
+ protected void hidePrompt() {
+ ((Combo) this.control).setText("");
+ }
+
+ /**
+ * High light prompt.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#highLightPrompt()
+ */
+ @Override
+ protected void highLightPrompt() {
+ }
+
+ /**
+ * Fill prompt text.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#fillPromptText()
+ */
+ @Override
+ protected void fillPromptText() {
+ final String promptText = PromptSupport.getPrompt(this.control);
+ if (promptText != null) {
+ this.control.getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ ((Combo) ComboFocusControlListener.this.control).setText(promptText);
+ }
+ });
+ }
+ }
+
+ /**
+ * Checks if is filled.
+ *
+ * @return true, if is filled
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#isFilled()
+ */
+ @Override
+ protected boolean isFilled() {
+ final String promptText = PromptSupport.getPrompt(this.control);
+ if (promptText != null && promptText.equals(((Combo) this.control).getText().trim())) {
+ return false;
+ }
+ return !"".equals(((Combo) this.control).getText().trim());
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/FocusControlListenerFactory.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/FocusControlListenerFactory.java
new file mode 100644
index 0000000..d23e002
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/FocusControlListenerFactory.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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.promptSupport;
+
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * This is a factory of focus/control listeners.
+ */
+class FocusControlListenerFactory {
+
+ /**
+ * Gets the focus control listener for.
+ *
+ * @param control control on which the listener will be added
+ * @return a BaseControlFocus Listener that can be attached to the events
+ * focusLost, focusGained and controlResized
+ */
+ static BaseFocusControlListener getFocusControlListenerFor(final Control control) {
+ if (control instanceof Combo) {
+ return new ComboFocusControlListener((Combo) control);
+ }
+ if (control instanceof CCombo) {
+ return new CComboFocusControlListener((CCombo) control);
+ }
+
+ if (control instanceof Text) {
+ return new TextFocusControlListener((Text) control);
+ }
+
+ if (control instanceof StyledText) {
+ return new StyledTextFocusControlListener((StyledText) control);
+ }
+ throw new IllegalArgumentException("Control should be a Text, a Combo, a CCombo or a StyledText widget");
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/PromptSupport.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/PromptSupport.java
new file mode 100644
index 0000000..69b9ea5
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/PromptSupport.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * 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.promptSupport;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * This utility class allows the user to add a prompt to a text or combo
+ * component (see http://designinginterfaces.com/Input_Prompt).<br/>
+ * This class is inspired by work of Peter Weishapl
+ */
+public class PromptSupport {
+
+ /**
+ * The Enum FocusBehavior.
+ */
+ public static enum FocusBehavior {
+ /**
+ * Highlight the prompt text as it would be selected.
+ */
+ HIGHLIGHT_PROMPT,
+ /**
+ * Hide the prompt text.
+ */
+ HIDE_PROMPT
+ };
+
+ /** The Constant KEY. */
+ private static final String KEY = "org.mihalis.opal.promptSupport.PromptSupport";
+
+ /** The Constant BACKGROUND. */
+ static final String BACKGROUND = KEY + ".background";
+
+ /** The Constant FOREGROUND. */
+ static final String FOREGROUND = KEY + ".foreground";
+
+ /** The Constant STYLE. */
+ static final String STYLE = KEY + ".style";
+
+ /** The Constant BEHAVIOR. */
+ static final String BEHAVIOR = KEY + ".behavior";
+
+ /** The Constant PROMPT. */
+ static final String PROMPT = KEY + ".prompt";
+
+ /** The Constant SET. */
+ static final String SET = KEY + ".set";
+
+ /**
+ * <p>
+ * Convenience method to set the <code>promptText</code> and
+ * <code>promptTextColor</code> on a {@link Control}.
+ * </p>
+ *
+ * @param promptText Prompt Text
+ * @param promptForeground Foreground
+ * @param promptBackground Background
+ * @param control control
+ * @exception IllegalArgumentException if the control is not a Text Box, a
+ * Combo Box, a StyledText or a CCombo
+ */
+ public static void init(final String promptText, final Color promptForeground, final Color promptBackground, final Control control) {
+ if (promptText != null && promptText.length() > 0) {
+ setPrompt(promptText, control);
+ }
+ if (promptForeground != null) {
+ setForeground(promptForeground, control);
+ }
+ if (promptBackground != null) {
+ setBackground(promptBackground, control);
+ }
+ }
+
+ /**
+ * Get the background color of the <code>control</code>, when no text is
+ * present. If no color has been set, the <code>control</code> background
+ * color will be returned.
+ *
+ * @param control the control
+ * @return the the background color of the text component, when no text is
+ * present
+ */
+ public static Color getBackground(final Control control) {
+ final Color temp = (Color) control.getData(BACKGROUND);
+ return temp == null ? control.getBackground() : temp;
+ }
+
+ /**
+ * <p>
+ * Sets the prompts background color on <code>control</code>. This
+ * background color will only be used when no text is present.
+ * </p>
+ *
+ * @param color the color
+ * @param control the control
+ * @exception IllegalArgumentException if the control is not a Text Box, a
+ * Combo Box, a StyledText or a CCombo
+ */
+ public static void setBackground(final Color color, final Control control) {
+ checkControl(control);
+ control.setData(BACKGROUND, color);
+ }
+
+ /**
+ * Get the {@link FocusBehavior} of <code>control</code>.
+ *
+ * @param control the control
+ * @return the {@link FocusBehavior} or {@link FocusBehavior#HIDE_PROMPT} if
+ * none is set
+ */
+ public static FocusBehavior getFocusBehavior(final Control control) {
+ final FocusBehavior temp = (FocusBehavior) control.getData(BEHAVIOR);
+ return temp == null ? FocusBehavior.HIDE_PROMPT : temp;
+
+ }
+
+ /**
+ * Sets the {@link FocusBehavior} on <code>control</code>, if it is the
+ * focus owner.
+ *
+ * @param focusBehavior the focus behavior
+ * @param control the control
+ * @exception IllegalArgumentException if the control is not a Text Box, a
+ * Combo Box, a StyledText or a CCombo
+ */
+ public static void setFocusBehavior(final FocusBehavior focusBehavior, final Control control) {
+ checkControl(control);
+ control.setData(BEHAVIOR, focusBehavior);
+ }
+
+ /**
+ * Returns the font style of the prompt text, which is a OR mix of
+ * SWT.ITALIC, SWT.NONE or SWT.BOLD
+ *
+ * @param control the control
+ * @return font style of the prompt text
+ */
+ public static int getFontStyle(final Control control) {
+ final Integer temp = (Integer) control.getData(STYLE);
+ return temp == null ? SWT.ITALIC : temp;
+
+ }
+
+ /**
+ * <p>
+ * Set the style of the prompt font, which is a OR mix of SWT.ITALIC,
+ * SWT.NONE or SWT.BOLD
+ * </p>
+ *
+ * @param fontStyle the font style
+ * @param control the control
+ * @exception IllegalArgumentException if the control is not a Text Box, a
+ * Combo Box, a StyledText or a CCombo
+ */
+ public static void setFontStyle(final int fontStyle, final Control control) {
+ checkControl(control);
+ control.setData(STYLE, fontStyle);
+ }
+
+ /**
+ * Get the foreground color of the prompt text. If no color has been set,
+ * the <code>GREY</code> color will be returned.
+ *
+ * @param control the control
+ * @return the color of the prompt text or <code>GREY</code>if none is set
+ */
+ public static Color getForeground(final Control control) {
+ final Color temp = (Color) control.getData(FOREGROUND);
+ return temp == null ? control.getForeground() : temp;
+
+ }
+
+ /**
+ * Sets the foreground color of the prompt on <code>control</code>. This
+ * color will be used when no text is present.
+ *
+ * @param color the color
+ * @param control the control
+ * @exception IllegalArgumentException if the control is not a Text Box, a
+ * Combo Box, a StyledText or a CCombo
+ */
+ public static void setForeground(final Color color, final Control control) {
+ checkControl(control);
+ control.setData(FOREGROUND, color);
+ }
+
+ /**
+ * Get the prompt text of <code>control</code>.
+ *
+ * @param control the control
+ * @return the prompt text
+ */
+ public static String getPrompt(final Control control) {
+ return (String) control.getData(PROMPT);
+ }
+
+ /**
+ * <p>
+ * Sets the prompt text on <code>control</code>
+ * </p>
+ * .
+ *
+ * @param promptText the prompt text
+ * @param control the control
+ * @exception IllegalArgumentException if the control is not a Text Box, a
+ * Combo Box, a StyledText or a CCombo
+ */
+ public static void setPrompt(final String promptText, final Control control) {
+ checkControl(control);
+
+ final boolean alreadySet = control.getData(SET) == null ? false : (Boolean) control.getData(SET);
+ if (alreadySet) {
+ throw new IllegalArgumentException("A prompt has already been set on this control !");
+ }
+ control.setData(PROMPT, promptText);
+
+ final BaseFocusControlListener focusControlListener = FocusControlListenerFactory.getFocusControlListenerFor(control);
+ control.addFocusListener(focusControlListener);
+ control.addControlListener(focusControlListener);
+ control.setData(SET, true);
+ }
+
+ /**
+ * Check if the control is a Text, a Combo, a StyledText or a CCombo.
+ *
+ * @param control control to check
+ */
+ private static void checkControl(final Control control) {
+ if (!(control instanceof Text) && !(control instanceof Combo) && !(control instanceof StyledText) && !(control instanceof CCombo)) {
+ throw new IllegalArgumentException("PromptSupport can only be used on a Text, a Combo, a StyledText or a CCombo widget.");
+ }
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/StyledTextFocusControlListener.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/StyledTextFocusControlListener.java
new file mode 100644
index 0000000..757bc73
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/StyledTextFocusControlListener.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * 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.promptSupport;
+
+import org.eclipse.swt.custom.StyledText;
+
+/**
+ * Focus/Control listener for a StyledText widget.
+ *
+ * @see StyledTextFocusControlEvent
+ */
+class StyledTextFocusControlListener extends BaseFocusControlListener {
+
+ /**
+ * Constructor.
+ *
+ * @param control control on which this listener will be attached
+ */
+ public StyledTextFocusControlListener(final StyledText control) {
+ super(control);
+ }
+
+ /**
+ * Hide prompt.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#hidePrompt()
+ */
+ @Override
+ protected void hidePrompt() {
+ ((StyledText) this.control).setText(EMPTY_STRING);
+ }
+
+ /**
+ * High light prompt.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#highLightPrompt()
+ */
+ @Override
+ protected void highLightPrompt() {
+ this.control.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ ((StyledText) StyledTextFocusControlListener.this.control).selectAll();
+
+ }
+ });
+ }
+
+ /**
+ * Fill prompt text.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#fillPromptText()
+ */
+ @Override
+ protected void fillPromptText() {
+ final String promptText = PromptSupport.getPrompt(this.control);
+ if (promptText != null) {
+ ((StyledText) this.control).setText(promptText);
+ }
+
+ }
+
+ /**
+ * Checks if is filled.
+ *
+ * @return true, if is filled
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#isFilled()
+ */
+ @Override
+ protected boolean isFilled() {
+ final String promptText = PromptSupport.getPrompt(this.control);
+ if (promptText != null && promptText.equals(((StyledText) this.control).getText().trim())) {
+ return false;
+ }
+ return !EMPTY_STRING.equals(((StyledText) this.control).getText().trim());
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/TextFocusControlListener.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/TextFocusControlListener.java
new file mode 100644
index 0000000..51f8465
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/promptSupport/TextFocusControlListener.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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.promptSupport;
+
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Focus/Control listener for a Text widget.
+ *
+ * @see TextFocusControlEvent
+ */
+class TextFocusControlListener extends BaseFocusControlListener {
+
+ /**
+ * Constructor.
+ *
+ * @param control control on which this listener will be attached
+ */
+ public TextFocusControlListener(final Text control) {
+ super(control);
+ }
+
+ /**
+ * Hide prompt.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#hidePrompt()
+ */
+ @Override
+ protected void hidePrompt() {
+ ((Text) this.control).setText(EMPTY_STRING);
+ }
+
+ /**
+ * High light prompt.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#highLightPrompt()
+ */
+ @Override
+ protected void highLightPrompt() {
+ // If we do a select all directly, it's not working !
+ this.control.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ ((Text) TextFocusControlListener.this.control).selectAll();
+ }
+ });
+ }
+
+ /**
+ * Fill prompt text.
+ *
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#fillPromptText()
+ */
+ @Override
+ protected void fillPromptText() {
+ final String promptText = PromptSupport.getPrompt(this.control);
+ if (promptText != null) {
+ ((Text) this.control).setText(promptText);
+ }
+ }
+
+ /**
+ * Checks if is filled.
+ *
+ * @return true, if is filled
+ * @see org.mihalis.opal.promptSupport.BaseFocusControlListener#isFilled()
+ */
+ @Override
+ protected boolean isFilled() {
+ final String promptText = PromptSupport.getPrompt(this.control);
+ if (promptText != null && promptText.equals(((Text) this.control).getText().trim())) {
+ return false;
+ }
+ return !EMPTY_STRING.equals(((Text) this.control).getText().trim());
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/AbstractPTWidget.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/AbstractPTWidget.java
new file mode 100644
index 0000000..7bece6a
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/AbstractPTWidget.java
@@ -0,0 +1,267 @@
+/*******************************************************************************
+ * 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.propertyTable;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.custom.StyledText;
+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.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+import org.mihalis.opal.utils.StringUtil;
+
+/**
+ * This abstract class contains all common methods for widgets that are part of
+ * a property table.
+ */
+public abstract class AbstractPTWidget implements PTWidget {
+
+ /** The parent property table. */
+ private PropertyTable parentPropertyTable;
+
+ /** The description label. */
+ protected StyledText descriptionLabel;
+
+ /**
+ * Refill data.
+ *
+ * @see org.mihalis.opal.propertyTable.PTWidget#refillData()
+ */
+ @Override
+ public abstract void refillData();
+
+ /**
+ * Build the widget itself.
+ *
+ * @param parent the parent
+ */
+ protected abstract void buildWidget(final Composite parent);
+
+ /**
+ * Builds the.
+ *
+ * @return the PT widget
+ * @see org.mihalis.opal.propertyTable.PTWidget#build()
+ */
+ @Override
+ public PTWidget build() {
+ Composite parent;
+ SashForm form = null;
+ if (parentPropertyTable.showDescription) {
+ form = new SashForm(parentPropertyTable, SWT.VERTICAL | SWT.BORDER);
+ form.setSashWidth(3);
+ form.setLayout(new GridLayout());
+
+ parent = new Composite(form, SWT.NONE);
+ parent.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+ } else {
+ parent = parentPropertyTable;
+ }
+ parent.setLayout(new GridLayout(3, false));
+
+ if (parentPropertyTable.showButtons) {
+ buildButtons(parent, parentPropertyTable.sorted, parentPropertyTable.styleOfView == PropertyTable.VIEW_AS_CATEGORIES, parentPropertyTable.showDescription);
+ }
+
+ buildWidget(parent);
+
+ if (parentPropertyTable.showDescription && form != null) { // check 'form' to satisfy SONAR
+ buildDescriptionPanel(form);
+ form.setWeights(new int[] { 90, 10 });
+ }
+
+ return this;
+ }
+
+ /**
+ * Build the buttons (Sort, switch category/flat list, show/hide
+ * description).
+ *
+ * @param parent parent composite
+ * @param sorted if <code>true</code>, the sort button is pushed
+ * @param showAsCategory if <code>true</code>, the "show as category" button
+ * is pushed
+ * @param showDescription if <code>true</code>, the "description" button is
+ * pushed
+ */
+ private void buildButtons(final Composite parent, final boolean sorted, final boolean showAsCategory, final boolean showDescription) {
+ buildSortButton(parent, sorted);
+ buildCategoryButton(parent, showAsCategory);
+ buildDescriptionButton(parent, showDescription);
+ }
+
+ /**
+ * Builds the sort button.
+ *
+ * @param parent parent composite
+ * @param sorted if <code>true</code>, the sort button is pushed
+ */
+ private void buildSortButton(final Composite parent, final boolean sorted) {
+ final Button sortButton = new Button(parent, SWT.FLAT | SWT.TOGGLE);
+ final ClassLoader loader = org.mihalis.opal.propertyTable.AbstractPTWidget.class.getClassLoader();
+ sortButton.setImage(new Image(parent.getDisplay(), loader.getResourceAsStream("images/sort.png")));
+ sortButton.setSelection(sorted);
+ sortButton.setToolTipText(ResourceManager.getLabel(ResourceManager.SORT_SHORT_DESCRIPTION));
+ sortButton.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false, 1, 1));
+
+ sortButton.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ getParentPropertyTable().sorted = !getParentPropertyTable().sorted;
+ refillData();
+ }
+ });
+
+ }
+
+ /**
+ * Builds the category button.
+ *
+ * @param parent parent composite
+ * @param showAsCategory if <code>true</code>, the "show as category" button
+ * is pushed
+ */
+ private void buildCategoryButton(final Composite parent, final boolean showAsCategory) {
+ final Button categoryButton = new Button(parent, SWT.FLAT | SWT.TOGGLE);
+ final ClassLoader loader = org.mihalis.opal.propertyTable.AbstractPTWidget.class.getClassLoader();
+ categoryButton.setImage(new Image(parent.getDisplay(), loader.getResourceAsStream("images/category.png")));
+ categoryButton.setSelection(showAsCategory);
+ categoryButton.setToolTipText(ResourceManager.getLabel(ResourceManager.CATEGORY_SHORT_DESCRIPTION));
+ categoryButton.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false, 1, 1));
+
+ categoryButton.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ if (getParentPropertyTable().styleOfView == PropertyTable.VIEW_AS_CATEGORIES) {
+ getParentPropertyTable().viewAsFlatList();
+ } else {
+ getParentPropertyTable().viewAsCategories();
+ }
+
+ }
+ });
+
+ }
+
+ /**
+ * Builds the description button.
+ *
+ * @param parent parent composite
+ * @param showDescription if <code>true</code>, the "description" button is
+ * pushed
+ */
+ private void buildDescriptionButton(final Composite parent, final boolean showDescription) {
+ final Button descriptionButton = new Button(parent, SWT.FLAT | SWT.TOGGLE);
+ final ClassLoader loader = org.mihalis.opal.propertyTable.AbstractPTWidget.class.getClassLoader();
+ descriptionButton.setImage(new Image(parent.getDisplay(), loader.getResourceAsStream("images/description.png")));
+ descriptionButton.setSelection(showDescription);
+ descriptionButton.setToolTipText(ResourceManager.getLabel(ResourceManager.DESCRIPTION_SHORT_DESCRIPTION));
+ descriptionButton.setLayoutData(new GridData(GridData.BEGINNING, GridData.FILL, true, false, 1, 1));
+
+ descriptionButton.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ if (getParentPropertyTable().showDescription) {
+ getParentPropertyTable().hideDescription();
+ } else {
+ getParentPropertyTable().showDescription();
+ }
+ }
+ });
+
+ }
+
+ /**
+ * Build the description panel.
+ *
+ * @param parent parent composite
+ */
+ private void buildDescriptionPanel(final Composite parent) {
+ descriptionLabel = new StyledText(parent, SWT.READ_ONLY);
+ descriptionLabel.setText("");
+ descriptionLabel.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 1, 1));
+ }
+
+ /**
+ * Dispose and build.
+ *
+ * @param table the table
+ * @return the PT widget
+ * @see org.mihalis.opal.propertyTable.PTWidget#disposeAndBuild(org.mihalis.opal.propertyTable.PropertyTable)
+ */
+ @Override
+ public PTWidget disposeAndBuild(final PropertyTable table) {
+ dispose();
+ return PTWidgetFactory.build(table);
+ }
+
+ /**
+ * Dispose the previous widget.
+ */
+ private void dispose() {
+ if (parentPropertyTable == null || parentPropertyTable.getChildren() == null) {
+ return;
+ }
+
+ for (final Control c : parentPropertyTable.getChildren()) {
+ c.dispose();
+ }
+ return;
+ }
+
+ /**
+ * Gets the parent property table.
+ *
+ * @return the parent PropertyTable
+ */
+ protected PropertyTable getParentPropertyTable() {
+ return parentPropertyTable;
+ }
+
+ /**
+ * Sets the parent property table.
+ *
+ * @param table the new parent property table
+ */
+ @Override
+ public void setParentPropertyTable(final PropertyTable table) {
+ parentPropertyTable = table;
+ }
+
+ /**
+ * Update description panel.
+ *
+ * @param selection the selection
+ * @see org.mihalis.opal.propertyTable.PTWidget#updateDescriptionPanel(java.lang.Object)
+ */
+ @Override
+ public void updateDescriptionPanel(final Object selection) {
+ if (selection == null || descriptionLabel == null) {
+ return;
+ }
+
+ final PTProperty selectedProperty = (PTProperty) selection;
+ descriptionLabel.setText(StringUtil.safeToString(selectedProperty.getDescription()));
+ SWTGraphicUtil.applyHTMLFormating(descriptionLabel);
+ descriptionLabel.update();
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTProperty.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTProperty.java
new file mode 100644
index 0000000..f73645e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTProperty.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * 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.propertyTable;
+
+import org.mihalis.opal.propertyTable.editor.PTEditor;
+
+/**
+ * Instances of this class are property stored in a PropertyTableWidget.
+ */
+public class PTProperty {
+
+ /** The name. */
+ private final String name;
+
+ /** The display name. */
+ private final String displayName;
+
+ /** The description. */
+ private final String description;
+
+ /** The value. */
+ private Object value;
+
+ /** The category. */
+ private String category;
+
+ /** The enabled. */
+ private boolean enabled = true;
+
+ /** The editor. */
+ private PTEditor editor;
+
+ /** The parent table. */
+ private PropertyTable parentTable;
+
+ /**
+ * Constructor.
+ *
+ * @param name name of the property
+ * @param displayName Name of the property displayed in the widget
+ * @param description Description of the property displayed in the widget
+ */
+ public PTProperty(final String name, final String displayName, final String description) {
+ this.name = name;
+ this.displayName = displayName;
+ this.description = description;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name name of the property
+ * @param displayName Name of the property displayed in the widget
+ * @param description Description of the property displayed in the widget
+ * @param value Initial value of the property
+ */
+ public PTProperty(final String name, final String displayName, final String description, final Object value) {
+ this(name, displayName, description);
+ this.value = value;
+ }
+
+ /**
+ * Gets the category.
+ *
+ * @return the category of the property
+ */
+ public String getCategory() {
+ return this.category;
+ }
+
+ /**
+ * Gets the description.
+ *
+ * @return the description of the property
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Gets the display name.
+ *
+ * @return the displayed name of the property
+ */
+ public String getDisplayName() {
+ return this.displayName;
+ }
+
+ /**
+ * Gets the editor.
+ *
+ * @return the editor associated to this property
+ */
+ public PTEditor getEditor() {
+ return this.editor;
+ }
+
+ /**
+ * Gets the name.
+ *
+ * @return the name of the property
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value of the property
+ */
+ public Object getValue() {
+ return this.value;
+ }
+
+ /**
+ * Checks if is enabled.
+ *
+ * @return <code>true</code> if the property is enabled, <code>false</code>
+ * otherwise
+ */
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ /**
+ * Sets the category.
+ *
+ * @param category category associated to this property
+ * @return the property
+ */
+ public PTProperty setCategory(final String category) {
+ this.category = category;
+ return this;
+ }
+
+ /**
+ * Sets the editor.
+ *
+ * @param editor editor associated to this property
+ * @return the property
+ */
+ public PTProperty setEditor(final PTEditor editor) {
+ this.editor = editor;
+ return this;
+ }
+
+ /**
+ * Sets the enabled.
+ *
+ * @param enabled if <code>true</code>, the property is enabled.
+ * @return the property
+ */
+ public PTProperty setEnabled(final boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ /**
+ * Sets the parent table.
+ *
+ * @param parentTable the property table associated to this property
+ * @return the property
+ */
+ public PTProperty setParentTable(final PropertyTable parentTable) {
+ this.parentTable = parentTable;
+ return this;
+ }
+
+ /**
+ * Sets the value.
+ *
+ * @param value the new value of the property
+ * @return the property
+ */
+ public PTProperty setValue(final Object value) {
+ this.value = value;
+ this.parentTable.firePTPropertyChangeListeners(this);
+ return this;
+ }
+
+ /**
+ * 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.name == null ? 0 : this.name.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 PTProperty other = (PTProperty) obj;
+ if (this.name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!this.name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTPropertyChangeListener.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTPropertyChangeListener.java
new file mode 100644
index 0000000..cffd690
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTPropertyChangeListener.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * 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.propertyTable;
+
+/**
+ * Classes which implement this interface provide methods that deal with the
+ * events that are generated when value of the property is changed.
+ *
+ * @see PTPropertyChangeEvent
+ */
+public interface PTPropertyChangeListener {
+ /**
+ * Sent when value is changed in a property.
+ *
+ * @param property property which value has changed
+ */
+ void propertyHasChanged(PTProperty property);
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidget.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidget.java
new file mode 100644
index 0000000..dde6bad
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidget.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * 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.propertyTable;
+
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Classes which implement this interface are widgets that may compose a
+ * PropertyTable (Table for Flat List, TableTree for Category).
+ */
+public interface PTWidget {
+
+ /**
+ * Build the widget (Table or TreeTable).
+ *
+ * @return the built widget
+ */
+ PTWidget build();
+
+ /**
+ * Dispose the previous widget and build a new one (when ones switch from
+ * Category View to Flat List view).
+ *
+ * @param table the PropertyTable to dispose
+ * @return the built widget
+ */
+ PTWidget disposeAndBuild(PropertyTable table);
+
+ /**
+ * Inject the parent property table in the widget.
+ *
+ * @param table table to inject
+ */
+ void setParentPropertyTable(final PropertyTable table);
+
+ /**
+ * Clear all data and fill the widget.
+ */
+ void refillData();
+
+ /**
+ * Gets the widget.
+ *
+ * @return the underlying widget (Table or TableTree)
+ */
+ Composite getWidget();
+
+ /**
+ * Update the description panel (if it exists).
+ *
+ * @param selection selected property
+ */
+ void updateDescriptionPanel(final Object selection);
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetFactory.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetFactory.java
new file mode 100644
index 0000000..4145373
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetFactory.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * 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.propertyTable;
+
+/**
+ * This class is a factory that builds the widget that is part of a property
+ * table.
+ */
+class PTWidgetFactory {
+
+ /**
+ * Build the widget displayed in a property table.
+ *
+ * @param table property table
+ * @return the widget
+ */
+ static PTWidget build(final PropertyTable table) {
+ PTWidget widget;
+ if (table.styleOfView == PropertyTable.VIEW_AS_FLAT_LIST) {
+ widget = new PTWidgetTable();
+ } else {
+ widget = new PTWidgetTree();
+ }
+ widget.setParentPropertyTable(table);
+ return widget;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetTable.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetTable.java
new file mode 100644
index 0000000..451ac4e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetTable.java
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * 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.propertyTable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ControlEditor;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.mihalis.opal.propertyTable.editor.PTStringEditor;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.StringUtil;
+
+/**
+ * Instances of this class are table that are displayed in a PropertyTable when
+ * the type of view is "Flat List".
+ */
+class PTWidgetTable extends AbstractPTWidget {
+
+ /** The table. */
+ private Table table;
+
+ /**
+ * Builds the widget.
+ *
+ * @param parent the parent
+ * @see org.mihalis.opal.propertyTable.AbstractPTWidget#buildWidget(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected void buildWidget(final Composite parent) {
+ this.table = new Table(parent, SWT.FULL_SELECTION);
+ this.table.setLinesVisible(true);
+ this.table.setHeaderVisible(true);
+ this.table.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 3, 1));
+
+ final TableColumn propertyColumn = new TableColumn(this.table, SWT.NONE);
+ propertyColumn.setText(ResourceManager.getLabel(ResourceManager.PROPERTY));
+
+ final TableColumn valueColumn = new TableColumn(this.table, SWT.NONE);
+ valueColumn.setText(ResourceManager.getLabel(ResourceManager.VALUE));
+
+ fillData();
+
+ this.table.addControlListener(new ControlAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse.swt.events.ControlEvent)
+ */
+ @Override
+ public void controlResized(final ControlEvent e) {
+ final Rectangle area = PTWidgetTable.this.table.getParent().getClientArea();
+ final Point size = PTWidgetTable.this.table.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+ final ScrollBar vBar = PTWidgetTable.this.table.getVerticalBar();
+ int width = area.width - PTWidgetTable.this.table.computeTrim(0, 0, 0, 0).width - vBar.getSize().x;
+ if (size.y > area.height + PTWidgetTable.this.table.getHeaderHeight()) {
+ // Subtract the scrollbar width from the total column width
+ // if a vertical scrollbar will be required
+ final Point vBarSize = vBar.getSize();
+ width -= vBarSize.x;
+ }
+ propertyColumn.pack();
+ valueColumn.setWidth(width - propertyColumn.getWidth());
+ PTWidgetTable.this.table.removeControlListener(this);
+ }
+
+ });
+
+ this.table.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ if (PTWidgetTable.this.table.getSelectionCount() == 0 || PTWidgetTable.this.table.getSelection()[0] == null) {
+ return;
+ }
+ updateDescriptionPanel(PTWidgetTable.this.table.getSelection()[0].getData());
+ }
+
+ });
+
+ }
+
+ /**
+ * Fill Data in the widget.
+ */
+ private void fillData() {
+ List<PTProperty> props;
+ if (getParentPropertyTable().sorted) {
+ props = new ArrayList<PTProperty>(getParentPropertyTable().getPropertiesAsList());
+ Collections.sort(props, new Comparator<PTProperty>() {
+
+ // multiple getName() calls replaced by assigning their results to local variables to satisfy SONAR!
+ @Override
+ public int compare(final PTProperty o1, final PTProperty o2) {
+ String o1Name = null;
+ String o2Name = null;
+
+ if ( o1 != null ) o1Name = o1.getName();
+ if ( o2 != null ) o2Name = o2.getName();
+
+ if ( o1Name == null && o2Name == null ) return 0; // NOSONAR
+ if ( o1Name == null && o2Name != null ) return -1; // NOSONAR
+ if ( o1Name != null && o2Name == null ) return 1; // NOSONAR
+
+ return o1Name.compareTo( o2Name ); // NOSONAR
+ }
+ });
+ } else {
+ props = getParentPropertyTable().getPropertiesAsList();
+ }
+
+ final List<ControlEditor> editors = new ArrayList<ControlEditor>();
+ for (final PTProperty p : props) {
+ final TableItem item = new TableItem(this.table, SWT.NONE);
+ item.setData(p);
+ item.setText(0, StringUtil.safeToString(p.getDisplayName()));
+ if (p.getEditor() == null) {
+ p.setEditor(new PTStringEditor());
+ }
+
+ final ControlEditor editor = p.getEditor().render(this, item, p);
+ item.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ if (editor.getEditor() != null) {
+ editor.getEditor().dispose();
+ }
+ editor.dispose();
+ }
+ });
+ if (!p.isEnabled()) {
+ item.setForeground(this.table.getDisplay().getSystemColor(SWT.COLOR_GRAY));
+ }
+ }
+
+ this.table.setData(editors);
+
+ }
+
+ /**
+ * Refill data.
+ *
+ * @see org.mihalis.opal.propertyTable.AbstractPTWidget#refillData()
+ */
+ @Override
+ public void refillData() {
+ for (final TableItem item : this.table.getItems()) {
+ item.dispose();
+ }
+
+ if (this.table.getData() != null) {
+ @SuppressWarnings("unchecked")
+ final List<ControlEditor> list = (List<ControlEditor>) this.table.getData();
+ for (final ControlEditor c : list) {
+ c.dispose();
+ }
+ list.clear();
+ this.table.setData(null);
+ }
+
+ fillData();
+
+ }
+
+ /**
+ * Gets the widget.
+ *
+ * @return the widget
+ * @see org.mihalis.opal.propertyTable.PTWidget#getWidget()
+ */
+ @Override
+ public Composite getWidget() {
+ return this.table;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetTree.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetTree.java
new file mode 100644
index 0000000..8dd0cd7
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PTWidgetTree.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * 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.propertyTable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ControlEditor;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.editor.PTStringEditor;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.StringUtil;
+
+/**
+ * Instances of this class are table that are displayed in a PropertyTable when
+ * the type of view is "Category".
+ */
+public class PTWidgetTree extends AbstractPTWidget {
+
+ /** The tree. */
+ private Tree tree;
+
+ /**
+ * Builds the widget.
+ *
+ * @param parent the parent
+ * @see org.mihalis.opal.propertyTable.AbstractPTWidget#buildWidget(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected void buildWidget(final Composite parent) {
+ this.tree = new Tree(parent, SWT.FULL_SELECTION);
+ this.tree.setLinesVisible(true);
+ this.tree.setHeaderVisible(true);
+ this.tree.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 3, 1));
+
+ final TreeColumn propertyColumn = new TreeColumn(this.tree, SWT.NONE);
+ propertyColumn.setText(ResourceManager.getLabel(ResourceManager.PROPERTY));
+
+ final TreeColumn valueColumn = new TreeColumn(this.tree, SWT.NONE);
+ valueColumn.setText(ResourceManager.getLabel(ResourceManager.VALUE));
+
+ fillData();
+ this.tree.addControlListener(new ControlAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse.swt.events.ControlEvent)
+ */
+ @Override
+ public void controlResized(final ControlEvent e) {
+ final Rectangle area = PTWidgetTree.this.tree.getParent().getClientArea();
+ final Point size = PTWidgetTree.this.tree.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+ final ScrollBar vBar = PTWidgetTree.this.tree.getVerticalBar();
+ int width = area.width - PTWidgetTree.this.tree.computeTrim(0, 0, 0, 0).width - vBar.getSize().x;
+ if (size.y > area.height + PTWidgetTree.this.tree.getHeaderHeight()) {
+ // Subtract the scrollbar width from the total column width
+ // if a vertical scrollbar will be required
+ final Point vBarSize = vBar.getSize();
+ width -= vBarSize.x;
+ }
+ propertyColumn.pack();
+ valueColumn.setWidth(width - propertyColumn.getWidth());
+ PTWidgetTree.this.tree.removeControlListener(this);
+ }
+
+ });
+
+ this.tree.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ if (PTWidgetTree.this.tree.getSelectionCount() == 0 || PTWidgetTree.this.tree.getSelection()[0] == null) {
+ return;
+ }
+ updateDescriptionPanel(PTWidgetTree.this.tree.getSelection()[0].getData());
+ }
+
+ });
+
+ }
+
+ /**
+ * Fill the data in the widget.
+ */
+ private void fillData() {
+ final Map<String, List<PTProperty>> data;
+
+ if (getParentPropertyTable().sorted) {
+ data = new TreeMap<String, List<PTProperty>>();
+ } else {
+ data = new HashMap<String, List<PTProperty>>();
+ }
+
+ for (final PTProperty p : getParentPropertyTable().getPropertiesAsList()) {
+ final String category = StringUtil.safeToString(p.getCategory());
+ if (!data.containsKey(category)) {
+ data.put(category, new ArrayList<PTProperty>());
+ }
+ data.get(category).add(p);
+ }
+
+ for (final Entry<String, List<PTProperty>> entry : data.entrySet()) {
+
+ if (entry.getValue() == null || entry.getValue().isEmpty()) {
+ continue;
+ }
+
+ final TreeItem root = new TreeItem(this.tree, SWT.NONE);
+ root.setText(0, entry.getKey());
+ root.setBackground(root.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+ root.setForeground(root.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ root.setExpanded(true);
+
+ for (final PTProperty p : entry.getValue()) {
+ final TreeItem item = new TreeItem(root, SWT.NONE);
+ item.setData(p);
+ item.setText(0, StringUtil.safeToString(p.getDisplayName()));
+ if (p.getEditor() == null) {
+ p.setEditor(new PTStringEditor());
+ }
+
+ final ControlEditor editor = p.getEditor().render(this, item, p);
+ item.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ if (editor.getEditor() != null) {
+ editor.getEditor().dispose();
+ }
+ editor.dispose();
+
+ }
+ });
+
+ if (!p.isEnabled()) {
+ item.setForeground(item.getDisplay().getSystemColor(SWT.COLOR_GRAY));
+ }
+ item.setExpanded(true);
+ }
+ root.setExpanded(true);
+
+ }
+
+ }
+
+ /**
+ * Refill data.
+ *
+ * @see org.mihalis.opal.propertyTable.AbstractPTWidget#refillData()
+ */
+ @Override
+ public void refillData() {
+ for (final TreeItem treeItem : this.tree.getItems()) {
+ treeItem.dispose();
+ }
+ fillData();
+ }
+
+ /**
+ * Gets the widget.
+ *
+ * @return the widget
+ * @see org.mihalis.opal.propertyTable.PTWidget#getWidget()
+ */
+ @Override
+ public Composite getWidget() {
+ return this.tree;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PropertyTable.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PropertyTable.java
new file mode 100644
index 0000000..34028a8
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/PropertyTable.java
@@ -0,0 +1,311 @@
+/*******************************************************************************
+ * 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.propertyTable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+/**
+ * Instances of this class are property sheets
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>PTPropertyChange</dd>
+ * </dl>
+ * </p>
+ * .
+ */
+public class PropertyTable extends Composite {
+
+ /** The Constant VIEW_AS_FLAT_LIST. */
+ final static int VIEW_AS_FLAT_LIST = 0;
+
+ /** The Constant VIEW_AS_CATEGORIES. */
+ final static int VIEW_AS_CATEGORIES = 1;
+
+ /** The show buttons. */
+ boolean showButtons;
+
+ /** The show description. */
+ boolean showDescription;
+
+ /** The sorted. */
+ boolean sorted;
+
+ /** The style of view. */
+ int styleOfView;
+
+ /** The properties. */
+ final List<PTProperty> properties;
+
+ /** The has been built. */
+ private boolean hasBeenBuilt = false;
+
+ /** The change listeners. */
+ private final List<PTPropertyChangeListener> changeListeners;
+
+ /** The widget. */
+ private PTWidget widget;
+
+ /**
+ * 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 PropertyTable(final Composite parent, final int style) {
+ super(parent, style);
+ setLayout(new FillLayout(SWT.VERTICAL));
+ showButtons = true;
+ showDescription = true;
+ sorted = true;
+ styleOfView = VIEW_AS_CATEGORIES;
+ properties = new ArrayList<PTProperty>();
+ changeListeners = new ArrayList<PTPropertyChangeListener>();
+
+ widget = PTWidgetFactory.build(this);
+
+ addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ // Draw the widget on first displaying
+ if (!hasBeenBuilt) {
+ widget.build();
+ hasBeenBuilt = true;
+ }
+ }
+ });
+
+ }
+
+ /**
+ * Add a change listener (event fired when the value of a property is
+ * changed).
+ *
+ * @param listener the listener
+ */
+ public void addChangeListener(final PTPropertyChangeListener listener) {
+ changeListeners.add(listener);
+ }
+
+ /**
+ * Add a property in this widget.
+ *
+ * @param property property to add
+ * @return the property
+ */
+ public PTProperty addProperty(final PTProperty property) {
+ if (properties.contains(property)) {
+ throw new IllegalArgumentException("A property called '" + property.getName() + "' has already been declared.");
+ }
+
+ properties.add(property);
+ property.setParentTable(this);
+ return property;
+ }
+
+ /**
+ * Fire the event "a value of a property has changed".
+ *
+ * @param property property which value has changed
+ */
+ public void firePTPropertyChangeListeners(final PTProperty property) {
+ for (final PTPropertyChangeListener listener : changeListeners) {
+ listener.propertyHasChanged(property);
+ }
+ }
+
+ /**
+ * Gets the properties.
+ *
+ * @return the values stored in this object in a map. Keys are property's
+ * name, values are values stored in a the property.
+ */
+ public Map<String, Object> getProperties() {
+ final Map<String, Object> map = new HashMap<String, Object>();
+ for (final PTProperty prop : properties) {
+ map.put(prop.getName(), prop.getValue());
+ }
+ return map;
+ }
+
+ /**
+ * Gets the properties as list.
+ *
+ * @return the properties stored in a list
+ */
+ public List<PTProperty> getPropertiesAsList() {
+ return new ArrayList<PTProperty>(properties);
+ }
+
+ /**
+ * Hide all buttons.
+ *
+ * @return this property table
+ */
+ public PropertyTable hideButtons() {
+ showButtons = false;
+ return rebuild();
+ }
+
+ /**
+ * Hide description.
+ *
+ * @return this property table
+ */
+ public PropertyTable hideDescription() {
+ showDescription = false;
+ return rebuild();
+ }
+
+ /**
+ * Rebuild the whole table.
+ *
+ * @return this property table
+ */
+ private PropertyTable rebuild() {
+ widget = widget.disposeAndBuild(this);
+ if (hasBeenBuilt) {
+ setLayout(new FillLayout());
+ widget.build();
+ layout();
+ }
+ return this;
+ }
+
+ /**
+ * Update the component when some values has changed.
+ */
+ public void refreshValues() {
+ rebuild();
+ }
+
+ /**
+ * Remove a change listener.
+ *
+ * @param listener listener to remove
+ */
+ public void removeChangeListener(final PTPropertyChangeListener listener) {
+ changeListeners.remove(listener);
+ }
+
+ /**
+ * Sets the properties.
+ *
+ * @param newValues the new values
+ */
+ public void setProperties(final Map<String, Object> newValues) {
+ for (final PTProperty prop : properties) {
+ if (newValues == null) {
+ prop.setValue(null);
+ } else {
+ final Object value = newValues.get(prop.getName());
+ prop.setValue(value);
+ }
+ }
+ rebuild();
+ }
+
+ /**
+ * Show all buttons.
+ *
+ * @return this property table
+ */
+ public PropertyTable showButtons() {
+ showButtons = true;
+ return rebuild();
+ }
+
+ /**
+ * Show description.
+ *
+ * @return this property table
+ */
+ public PropertyTable showDescription() {
+ showDescription = true;
+ return rebuild();
+ }
+
+ /**
+ * Sort the properties.
+ *
+ * @return this property table
+ */
+ public PropertyTable sort() {
+ sorted = true;
+ widget.refillData();
+ return this;
+ }
+
+ /**
+ * Show properties not sorted.
+ *
+ * @return this property table
+ */
+ public PropertyTable unsort() {
+ sorted = false;
+ widget.refillData();
+ return this;
+
+ }
+
+ /**
+ * View the properties as categories.
+ *
+ * @return this property table
+ */
+ public PropertyTable viewAsCategories() {
+ styleOfView = VIEW_AS_CATEGORIES;
+ return rebuild();
+ }
+
+ /**
+ * View the properties as a flat list.
+ *
+ * @return this property table
+ */
+ public PropertyTable viewAsFlatList() {
+ styleOfView = VIEW_AS_FLAT_LIST;
+ return rebuild();
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTBaseTextEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTBaseTextEditor.java
new file mode 100644
index 0000000..eb55d09
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTBaseTextEditor.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ControlEditor;
+import org.eclipse.swt.custom.TableEditor;
+import org.eclipse.swt.custom.TreeEditor;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+import org.mihalis.opal.utils.StringUtil;
+
+/**
+ * This abstract class represents all text-based editors (float editor, integer
+ * editor, password editor, String editor, URL editor).
+ */
+public abstract class PTBaseTextEditor extends PTEditor {
+
+ /** The text. */
+ protected Text text;
+
+ /**
+ * Render.
+ *
+ * @param widget the widget
+ * @param item the item
+ * @param property the property
+ * @return the control editor
+ * @see org.mihalis.opal.propertyTable.editor.PTEditor#render(org.mihalis.opal.propertyTable.PTWidget,
+ * org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ public ControlEditor render(final PTWidget widget, final Item item, final PTProperty property) {
+
+ ControlEditor editor;
+ if (widget.getWidget() instanceof Table) {
+ editor = new TableEditor((Table) widget.getWidget());
+ } else {
+ editor = new TreeEditor((Tree) widget.getWidget());
+ }
+
+ widget.updateDescriptionPanel(property);
+
+ this.text = new Text(widget.getWidget(), getStyle());
+
+ addVerifyListeners();
+
+ this.text.setText(StringUtil.safeToString(property.getValue()));
+ this.text.addListener(SWT.Modify, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ property.setValue(convertValue());
+ }
+ });
+
+ this.text.addListener(SWT.FocusIn, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ widget.updateDescriptionPanel(property);
+ }
+ });
+
+ editor.grabHorizontal = true;
+ if (widget.getWidget() instanceof Table) {
+ ((TableEditor) editor).setEditor(this.text, (TableItem) item, 1);
+ } else {
+ ((TreeEditor) editor).setEditor(this.text, (TreeItem) item, 1);
+ }
+
+ this.text.setEnabled(property.isEnabled());
+
+ return editor;
+ }
+
+ /**
+ * Add the verify listeners.
+ */
+ public abstract void addVerifyListeners();
+
+ /**
+ * Convert value.
+ *
+ * @return the value of the data typed by the user in the correct format
+ */
+ public abstract Object convertValue();
+
+ /**
+ * Gets the style.
+ *
+ * @return the style (SWT.NONE or SWT.PASSWORD)
+ */
+ public abstract int getStyle();
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTCheckboxEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTCheckboxEditor.java
new file mode 100644
index 0000000..52f1e4f
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTCheckboxEditor.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ControlEditor;
+import org.eclipse.swt.custom.TableEditor;
+import org.eclipse.swt.custom.TreeEditor;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+
+/**
+ * This editor is a check box for boolean values.
+ */
+public class PTCheckboxEditor extends PTEditor {
+
+ /**
+ * Render.
+ *
+ * @param widget the widget
+ * @param item the item
+ * @param property the property
+ * @return the control editor
+ * @see org.mihalis.opal.propertyTable.editor.PTEditor#render(org.mihalis.opal.propertyTable.PTWidget,
+ * org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ public ControlEditor render(final PTWidget widget, final Item item, final PTProperty property) {
+ ControlEditor editor;
+ if (widget.getWidget() instanceof Table) {
+ editor = new TableEditor((Table) widget.getWidget());
+ } else {
+ editor = new TreeEditor((Tree) widget.getWidget());
+ }
+
+ final Button button = new Button(widget.getWidget(), SWT.CHECK);
+
+ if (property.getValue() == null) {
+ button.setSelection(false);
+ } else {
+ button.setSelection(((Boolean) property.getValue()).booleanValue());
+ }
+
+ button.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ property.setValue(Boolean.valueOf(button.getSelection()));
+ }
+ });
+
+ button.addListener(SWT.FocusIn, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ widget.updateDescriptionPanel(property);
+ }
+ });
+
+ button.pack();
+ editor.minimumWidth = button.getSize().x;
+ editor.horizontalAlignment = SWT.LEFT;
+ if (widget.getWidget() instanceof Table) {
+ ((TableEditor) editor).setEditor(button, (TableItem) item, 1);
+ } else {
+ ((TreeEditor) editor).setEditor(button, (TreeItem) item, 1);
+ }
+
+ button.setEnabled(property.isEnabled());
+
+ return editor;
+
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTChooserEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTChooserEditor.java
new file mode 100644
index 0000000..440ffd1
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTChooserEditor.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ControlEditor;
+import org.eclipse.swt.custom.TableEditor;
+import org.eclipse.swt.custom.TreeEditor;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This abstract class represents a chooser. A chooser is composed of :
+ * <ul>
+ * <li>a displayed value (text)
+ * <li>a "X" button to erase the value (set to null)
+ * <li>a "..." button to open an extra window to set up the value
+ * </ul>
+ *
+ */
+public abstract class PTChooserEditor extends PTEditor {
+
+ /** The widget. */
+ private PTWidget widget;
+
+ /** The item. */
+ private Item item;
+
+ /** The property. */
+ private PTProperty property;
+
+ /**
+ * Render.
+ *
+ * @param widget the widget
+ * @param item the item
+ * @param property the property
+ * @return the control editor
+ * @see org.mihalis.opal.propertyTable.editor.PTEditor#render(org.mihalis.opal.propertyTable.PTWidget,
+ * org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ public ControlEditor render(final PTWidget widget, final Item item, final PTProperty property) {
+ this.widget = widget;
+ this.item = item;
+ this.property = property;
+
+ if (item instanceof TableItem) {
+ ((TableItem) item).setText(1, getTextFor(property));
+ } else {
+ ((TreeItem) item).setText(1, getTextFor(property));
+ }
+
+ final Color bgColor = getBackgroundColor(property);
+ if (bgColor != null) {
+ if (item instanceof TableItem) {
+ ((TableItem) item).setBackground(1, bgColor);
+ }
+ if (item instanceof TreeItem) {
+ ((TreeItem) item).setBackground(1, bgColor);
+ }
+ SWTGraphicUtil.addDisposer(item, bgColor);
+ }
+
+ ControlEditor editor;
+ if (widget.getWidget() instanceof Table) {
+ editor = new TableEditor((Table) widget.getWidget());
+ } else {
+ editor = new TreeEditor((Tree) widget.getWidget());
+ }
+
+ final Composite buttonHolder = new Composite(widget.getWidget(), SWT.NONE);
+ final FillLayout buttonHolderLayout = new FillLayout(SWT.HORIZONTAL);
+ buttonHolderLayout.marginWidth = buttonHolderLayout.marginHeight = 0;
+ buttonHolder.setLayout(buttonHolderLayout);
+
+ createEraseButton(buttonHolder);
+ createPlusButton(buttonHolder);
+
+ buttonHolder.pack();
+ editor.minimumWidth = buttonHolder.getSize().x;
+ editor.horizontalAlignment = SWT.RIGHT;
+
+ if (widget.getWidget() instanceof Table) {
+ ((TableEditor) editor).setEditor(buttonHolder, (TableItem) item, 1);
+ } else {
+ ((TreeEditor) editor).setEditor(buttonHolder, (TreeItem) item, 1);
+ }
+
+ return editor;
+ }
+
+ /**
+ * Creates the "erase" button.
+ *
+ * @param buttonHolder parent composite
+ */
+ private void createEraseButton(final Composite buttonHolder) {
+ final Button eraseButton = new Button(buttonHolder, SWT.PUSH);
+ eraseButton.setText(" X ");
+ eraseButton.setToolTipText(ResourceManager.getLabel(ResourceManager.ERASE_PROPERTY));
+ eraseButton.setEnabled(this.property.isEnabled());
+ eraseButton.pack();
+
+ eraseButton.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ PTChooserEditor.this.property.setValue(null);
+ if (PTChooserEditor.this.item instanceof TableItem) {
+ ((TableItem) PTChooserEditor.this.item).setBackground(1, Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+ ((TableItem) PTChooserEditor.this.item).setText(1, getTextFor(PTChooserEditor.this.property));
+ }
+ if (PTChooserEditor.this.item instanceof TreeItem) {
+ ((TreeItem) PTChooserEditor.this.item).setBackground(1, Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+ ((TreeItem) PTChooserEditor.this.item).setText(1, getTextFor(PTChooserEditor.this.property));
+ }
+ }
+ });
+
+ eraseButton.addListener(SWT.FocusIn, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ PTChooserEditor.this.widget.updateDescriptionPanel(PTChooserEditor.this.property);
+ }
+ });
+ }
+
+ /**
+ * Creates the "plus" button.
+ *
+ * @param buttonHolder aprent composite
+ */
+ private void createPlusButton(final Composite buttonHolder) {
+ final Button plusButton = new Button(buttonHolder, SWT.PUSH);
+ plusButton.setText("...");
+ plusButton.setToolTipText(ResourceManager.getLabel(ResourceManager.EDIT_PROPERTY));
+ plusButton.setEnabled(this.property.isEnabled());
+
+ plusButton.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ openWindow(PTChooserEditor.this.widget, PTChooserEditor.this.item, PTChooserEditor.this.property);
+ }
+ });
+
+ plusButton.addListener(SWT.FocusIn, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ PTChooserEditor.this.widget.updateDescriptionPanel(PTChooserEditor.this.property);
+ }
+ });
+
+ plusButton.pack();
+ }
+
+ /**
+ * Open the window to edit the property.
+ *
+ * @param widget parent widget
+ * @param item item
+ * @param property edited property
+ */
+ protected abstract void openWindow(PTWidget widget, Item item, PTProperty property);
+
+ /**
+ * Gets the text for.
+ *
+ * @param property property
+ * @return the string representation of the value stored in the property
+ */
+ protected abstract String getTextFor(PTProperty property);
+
+ /**
+ * Get the background color of an item.
+ *
+ * @param property property
+ * @return a background color (for the PTColorEditor) or null (for other
+ * editors).
+ */
+ protected abstract Color getBackgroundColor(PTProperty property);
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTColorEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTColorEditor.java
new file mode 100644
index 0000000..387ade3
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTColorEditor.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.ColorDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * A color editor.
+ */
+public class PTColorEditor extends PTChooserEditor {
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#openWindow(org.mihalis.opal.propertyTable.PTWidget, org.eclipse.swt.widgets.Item, org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void openWindow(final PTWidget widget, final Item item, final PTProperty property) {
+ final ColorDialog dialog = new ColorDialog(widget.getWidget().getShell());
+ final RGB result = dialog.open();
+ if (result != null) {
+ property.setValue(result);
+
+ final Color bgColor = getBackgroundColor(property);
+ if (bgColor != null) {
+ if (item instanceof TableItem) {
+ ((TableItem) item).setBackground(1, bgColor);
+ }
+ if (item instanceof TreeItem) {
+ ((TreeItem) item).setBackground(1, bgColor);
+ }
+ SWTGraphicUtil.addDisposer(item, bgColor);
+ }
+
+ if (item instanceof TableItem) {
+ ((TableItem) item).setText(1, getTextFor(property));
+
+ } else {
+ ((TreeItem) item).setText(1, getTextFor(property));
+ }
+ }
+ }
+
+ /**
+ * Gets the text for.
+ *
+ * @param property the property
+ * @return the text for
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getTextFor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected String getTextFor(final PTProperty property) {
+
+ if (property.getValue() == null) {
+ return "";
+ }
+
+ final RGB rgb = (RGB) property.getValue();
+
+ final StringBuilder sb = new StringBuilder();
+ sb.append("R:").append(rgb.red).append(" G:").append(rgb.green).append(" B:").append(rgb.blue);
+ sb.append(" - #");
+ sb.append(("0" + Integer.toHexString(rgb.red)).substring(0, 2));
+ sb.append(("0" + Integer.toHexString(rgb.green)).substring(0, 2));
+ sb.append(("0" + Integer.toHexString(rgb.blue)).substring(0, 2));
+ return sb.toString();
+ }
+
+ /**
+ * Gets the background color.
+ *
+ * @param property the property
+ * @return the background color
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getBackgroundColor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected Color getBackgroundColor(final PTProperty property) {
+ if (property.getValue() == null) {
+ return null;
+ }
+ final RGB rgb = (RGB) property.getValue();
+ return new Color(Display.getDefault(), rgb);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTComboEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTComboEditor.java
new file mode 100644
index 0000000..b8c4848
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTComboEditor.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.custom.ControlEditor;
+import org.eclipse.swt.custom.TableEditor;
+import org.eclipse.swt.custom.TreeEditor;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+
+/**
+ * This editor is for combo values. By default, the combo is editable
+ */
+public class PTComboEditor extends PTEditor {
+
+ /** The read only. */
+ private final boolean readOnly;
+
+ /** The data. */
+ private final List<Object> data;
+
+ /**
+ * Constructor.
+ *
+ * @param readOnly if true, the combo is read-only
+ * @param data data displayed in the combo
+ */
+ public PTComboEditor(final boolean readOnly, final Object... data) {
+ this.readOnly = readOnly;
+ this.data = new ArrayList<Object>(Arrays.asList(data));
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param data data displayed in the combo.
+ */
+ public PTComboEditor(final Object... data) {
+ this.readOnly = false;
+ this.data = new ArrayList<Object>(Arrays.asList(data));
+ }
+
+ /**
+ * Render.
+ *
+ * @param widget the widget
+ * @param item the item
+ * @param property the property
+ * @return the control editor
+ * @see org.mihalis.opal.propertyTable.editor.PTEditor#render(org.mihalis.opal.propertyTable.PTWidget,
+ * org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ public ControlEditor render(final PTWidget widget, final Item item, final PTProperty property) {
+ ControlEditor editor;
+ if (widget.getWidget() instanceof Table) {
+ editor = new TableEditor((Table) widget.getWidget());
+ } else {
+ editor = new TreeEditor((Tree) widget.getWidget());
+ }
+
+ final CCombo combo = new CCombo(widget.getWidget(), SWT.BORDER | (this.readOnly ? SWT.READ_ONLY : SWT.NONE));
+
+ for (int i = 0; i < this.data.size(); i++) {
+ final Object datum = this.data.get(i);
+ combo.add(datum.toString());
+ if (datum.equals(property.getValue())) {
+ combo.select(i);
+ }
+ }
+
+ combo.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ property.setValue(PTComboEditor.this.data.get(combo.getSelectionIndex()));
+ }
+ });
+
+ combo.addListener(SWT.FocusIn, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ widget.updateDescriptionPanel(property);
+ }
+ });
+
+ editor.grabHorizontal = false;
+ editor.horizontalAlignment = SWT.LEFT;
+ editor.minimumWidth = 200;
+ if (widget.getWidget() instanceof Table) {
+ ((TableEditor) editor).setEditor(combo, (TableItem) item, 1);
+ } else {
+ ((TreeEditor) editor).setEditor(combo, (TreeItem) item, 1);
+ }
+ return editor;
+
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDateEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDateEditor.java
new file mode 100644
index 0000000..0e57a7b
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDateEditor.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ControlEditor;
+import org.eclipse.swt.custom.TableEditor;
+import org.eclipse.swt.custom.TreeEditor;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.DateTime;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+
+/**
+ * This editor allows the user to enter dates.
+ */
+public class PTDateEditor extends PTEditor {
+
+ /**
+ * Render.
+ *
+ * @param widget the widget
+ * @param item the item
+ * @param property the property
+ * @return the control editor
+ * @see org.mihalis.opal.propertyTable.editor.PTEditor#render(org.mihalis.opal.propertyTable.PTWidget,
+ * org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ public ControlEditor render(final PTWidget widget, final Item item, final PTProperty property) {
+ ControlEditor editor;
+ if (widget.getWidget() instanceof Table) {
+ editor = new TableEditor((Table) widget.getWidget());
+ } else {
+ editor = new TreeEditor((Tree) widget.getWidget());
+ }
+
+ final DateTime dateEditor = new DateTime(widget.getWidget(), SWT.DATE | SWT.MEDIUM | SWT.DROP_DOWN);
+ final Date date = (Date) property.getValue();
+ final Calendar c = Calendar.getInstance();
+
+ if (date != null) {
+ c.setTime(date);
+ dateEditor.setDate(c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
+ }
+
+ dateEditor.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ c.setTime(new Date());
+ c.clear();
+ c.set(dateEditor.getYear(), dateEditor.getMonth(), dateEditor.getDay());
+ property.setValue(c.getTime());
+ }
+ });
+
+ dateEditor.addListener(SWT.FocusIn, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ widget.updateDescriptionPanel(property);
+ }
+ });
+
+ editor.grabHorizontal = true;
+ editor.horizontalAlignment = SWT.LEFT;
+
+ if (widget.getWidget() instanceof Table) {
+ ((TableEditor) editor).setEditor(dateEditor, (TableItem) item, 1);
+ } else {
+ ((TreeEditor) editor).setEditor(dateEditor, (TreeItem) item, 1);
+ }
+
+ dateEditor.setEnabled(property.isEnabled());
+
+ return editor;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDimensionEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDimensionEditor.java
new file mode 100644
index 0000000..d416b7b
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDimensionEditor.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import java.awt.Dimension;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * Editor for {@link Dimension} values.
+ */
+public class PTDimensionEditor extends PTWindowEditor {
+
+ /** The width. */
+ private Text width;
+
+ /** The height. */
+ private Text height;
+
+ /**
+ * Creates the content.
+ *
+ * @param shell the shell
+ * @param property the property
+ * @see org.mihalis.opal.propertyTable.editor.PTWindowEditor#createContent(org.eclipse.swt.widgets.Shell,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void createContent(final Shell shell, final PTProperty property) {
+ final Label widthLabel = new Label(shell, SWT.NONE);
+ widthLabel.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+ widthLabel.setText(ResourceManager.getLabel(ResourceManager.WIDTH));
+
+ this.width = new Text(shell, SWT.BORDER);
+ this.width.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ if (property.getValue() != null) {
+ final Dimension d = (Dimension) property.getValue();
+ this.width.setText(String.valueOf(d.width));
+ }
+ addVerifyListeners(this.width);
+
+ final Label heightLabel = new Label(shell, SWT.NONE);
+ heightLabel.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+ heightLabel.setText(ResourceManager.getLabel(ResourceManager.HEIGHT));
+
+ this.height = new Text(shell, SWT.BORDER);
+ this.height.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ if (property.getValue() != null) {
+ final Dimension d = (Dimension) property.getValue();
+ this.height.setText(String.valueOf(d.height));
+ }
+ addVerifyListeners(this.height);
+
+ }
+
+ /**
+ * Fill property.
+ *
+ * @param item the item
+ * @param property the property
+ * @see org.mihalis.opal.propertyTable.editor.PTWindowEditor#fillProperty(org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void fillProperty(final Item item, final PTProperty property) {
+ final Dimension d = new Dimension();
+ d.width = getIntValue(this.width);
+ d.height = getIntValue(this.height);
+ property.setValue(d);
+ if (item instanceof TableItem) {
+ ((TableItem) item).setText(1, getTextFor(property));
+ } else {
+ ((TreeItem) item).setText(1, getTextFor(property));
+ }
+ }
+
+ /**
+ * Gets the text for.
+ *
+ * @param property the property
+ * @return the text for
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getTextFor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected String getTextFor(final PTProperty property) {
+ if (property.getValue() == null) {
+ return "(null)";
+ }
+ final Dimension d = (Dimension) property.getValue();
+ return "[" + d.width + "," + d.height + "]";
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDirectoryEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDirectoryEditor.java
new file mode 100644
index 0000000..f54ea08
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTDirectoryEditor.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.StringUtil;
+
+/**
+ * This editor allows user to select a directory.
+ */
+public class PTDirectoryEditor extends PTChooserEditor {
+
+ /**
+ * Open window.
+ *
+ * @param widget the widget
+ * @param item the item
+ * @param property the property
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#openWindow(org.mihalis.opal.propertyTable.PTWidget,
+ * org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void openWindow(final PTWidget widget, final Item item, final PTProperty property) {
+ final DirectoryDialog dialog = new DirectoryDialog(widget.getWidget().getShell());
+ dialog.setMessage(ResourceManager.getLabel(ResourceManager.CHOOSE_DIRECTORY));
+ final String result = dialog.open();
+ if (result != null) {
+ if (item instanceof TableItem) {
+ ((TableItem) item).setText(1, result);
+ } else {
+ ((TreeItem) item).setText(1, result);
+ }
+ property.setValue(result);
+ }
+
+ }
+
+ /**
+ * Gets the text for.
+ *
+ * @param property the property
+ * @return the text for
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getTextFor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected String getTextFor(final PTProperty property) {
+ return StringUtil.safeToString(property.getValue());
+ }
+
+ /**
+ * Gets the background color.
+ *
+ * @param property the property
+ * @return the background color
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getBackgroundColor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected Color getBackgroundColor(final PTProperty property) {
+ return null;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTEditor.java
new file mode 100644
index 0000000..0de319c
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTEditor.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.custom.ControlEditor;
+import org.eclipse.swt.widgets.Item;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+
+/**
+ * This abstract class represents a Property Table Editor. An editor is a widget
+ * that allows one to modify a property
+ *
+ */
+public abstract class PTEditor {
+
+ /**
+ * Renders an editor.
+ *
+ * @param parent the parent PTWidget (a table or a tree table)
+ * @param item the item on which the editor is displayed
+ * @param property the property associated to the editor
+ * @return a control editor
+ */
+ public abstract ControlEditor render(PTWidget parent, Item item, PTProperty property);
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFileEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFileEditor.java
new file mode 100644
index 0000000..5a272ef
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFileEditor.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+import org.mihalis.opal.utils.StringUtil;
+
+/**
+ * This editor allows user to select a file.
+ */
+public class PTFileEditor extends PTChooserEditor {
+
+ /**
+ * Open window.
+ *
+ * @param widget the widget
+ * @param item the item
+ * @param property the property
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#openWindow(org.mihalis.opal.propertyTable.PTWidget,
+ * org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void openWindow(final PTWidget widget, final Item item, final PTProperty property) {
+ final FileDialog dialog = new FileDialog(widget.getWidget().getShell(), SWT.OPEN);
+ final String result = dialog.open();
+ if (result != null) {
+ if (item instanceof TableItem) {
+ ((TableItem) item).setText(1, result);
+ } else {
+ ((TreeItem) item).setText(1, result);
+ }
+ property.setValue(result);
+ }
+
+ }
+
+ /**
+ * Gets the text for.
+ *
+ * @param property the property
+ * @return the text for
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getTextFor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected String getTextFor(final PTProperty property) {
+ return StringUtil.safeToString(property.getValue());
+ }
+
+ /**
+ * Gets the background color.
+ *
+ * @param property the property
+ * @return the background color
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getBackgroundColor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected Color getBackgroundColor(final PTProperty property) {
+ return null;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFloatEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFloatEditor.java
new file mode 100644
index 0000000..af68b97
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFloatEditor.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.events.VerifyListener;
+import org.mihalis.opal.utils.StringUtil;
+
+/**
+ * This editor is used to edit float values.
+ */
+public class PTFloatEditor extends PTBaseTextEditor {
+
+ /**
+ * Adds the verify listeners.
+ *
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#addVerifyListeners()
+ */
+ @Override
+ public void addVerifyListeners() {
+ 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.character != '.' && e.character != ',') {
+ e.doit = false;
+ return;
+ }
+
+ e.doit = verifyEntry(e.text, e.keyCode);
+
+ }
+ });
+ }
+
+ /**
+ * Check if an entry is a float.
+ *
+ * @param entry text typed by the user
+ * @param keyCode key code
+ * @return true if the user typed a float value, false otherwise
+ */
+ private boolean verifyEntry(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 {
+ Double.parseDouble(work.replace(',', '.'));
+ } catch (final NumberFormatException nfe) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Convert value.
+ *
+ * @return the object
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#convertValue()
+ */
+ @Override
+ public Object convertValue() {
+ return Float.parseFloat(this.text.getText());
+ }
+
+ /**
+ * Gets the style.
+ *
+ * @return the style
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#getStyle()
+ */
+ @Override
+ public int getStyle() {
+ return SWT.NONE;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFontEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFontEditor.java
new file mode 100644
index 0000000..daedb99
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTFontEditor.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.widgets.FontDialog;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * This editor is a font editor.
+ */
+public class PTFontEditor extends PTChooserEditor {
+
+ /**
+ * Open window.
+ *
+ * @param widget the widget
+ * @param item the item
+ * @param property the property
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#openWindow(org.mihalis.opal.propertyTable.PTWidget,
+ * org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void openWindow(final PTWidget widget, final Item item, final PTProperty property) {
+ final FontDialog dialog = new FontDialog(widget.getWidget().getShell());
+ final FontData result = dialog.open();
+ if (result != null && result.getName() != null && !"".equals(result.getName().trim())) {
+ property.setValue(result);
+ if (item instanceof TableItem) {
+ ((TableItem) item).setText(1, getTextFor(property));
+ } else {
+ ((TreeItem) item).setText(1, getTextFor(property));
+ }
+ }
+ }
+
+ /**
+ * Gets the text for.
+ *
+ * @param property the property
+ * @return the text for
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getTextFor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected String getTextFor(final PTProperty property) {
+ if (property.getValue() == null) {
+ return "";
+ }
+
+ final FontData fontData = (FontData) property.getValue();
+
+ final StringBuilder sb = new StringBuilder();
+ if (fontData != null) {
+ sb.append(fontData.getName()).append(",").append(fontData.getHeight()).append(" pt");
+ if ((fontData.getStyle() & SWT.BOLD) == SWT.BOLD) {
+ sb.append(", ").append(ResourceManager.getLabel(ResourceManager.BOLD));
+ }
+ if ((fontData.getStyle() & SWT.ITALIC) == SWT.ITALIC) {
+ sb.append(", ").append(ResourceManager.getLabel(ResourceManager.ITALIC));
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Gets the background color.
+ *
+ * @param property the property
+ * @return the background color
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getBackgroundColor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected Color getBackgroundColor(final PTProperty property) {
+ return null;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTInsetsEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTInsetsEditor.java
new file mode 100644
index 0000000..8556a0c
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTInsetsEditor.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import java.awt.Insets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * Editor for {@link Insets} values.
+ */
+public class PTInsetsEditor extends PTWindowEditor {
+
+ /** The top. */
+ private Text top;
+
+ /** The left. */
+ private Text left;
+
+ /** The right. */
+ private Text right;
+
+ /** The bottom. */
+ private Text bottom;
+
+ /**
+ * Creates the content.
+ *
+ * @param shell the shell
+ * @param property the property
+ * @see org.mihalis.opal.propertyTable.editor.PTWindowEditor#createContent(org.eclipse.swt.widgets.Shell,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void createContent(final Shell shell, final PTProperty property) {
+ final Label topLabel = new Label(shell, SWT.NONE);
+ topLabel.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+ topLabel.setText(ResourceManager.getLabel(ResourceManager.TOP));
+
+ this.top = new Text(shell, SWT.BORDER);
+ this.top.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ if (property.getValue() != null) {
+ final Insets insets = (Insets) property.getValue();
+ this.top.setText(String.valueOf(insets.top));
+ }
+ addVerifyListeners(this.top);
+
+ final Label heightLabel = new Label(shell, SWT.NONE);
+ heightLabel.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+ heightLabel.setText(ResourceManager.getLabel(ResourceManager.LEFT));
+
+ this.left = new Text(shell, SWT.BORDER);
+ this.left.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ if (property.getValue() != null) {
+ final Insets insets = (Insets) property.getValue();
+ this.left.setText(String.valueOf(insets.left));
+ }
+ addVerifyListeners(this.left);
+
+ final Label bottomLabel = new Label(shell, SWT.NONE);
+ bottomLabel.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+ bottomLabel.setText(ResourceManager.getLabel(ResourceManager.BOTTOM));
+
+ this.bottom = new Text(shell, SWT.BORDER);
+ this.bottom.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ if (property.getValue() != null) {
+ final Insets insets = (Insets) property.getValue();
+ this.bottom.setText(String.valueOf(insets.bottom));
+ }
+ addVerifyListeners(this.bottom);
+
+ final Label rightLabel = new Label(shell, SWT.NONE);
+ rightLabel.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+ rightLabel.setText(ResourceManager.getLabel(ResourceManager.RIGHT));
+
+ this.right = new Text(shell, SWT.BORDER);
+ this.right.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ if (property.getValue() != null) {
+ final Insets insets = (Insets) property.getValue();
+ this.right.setText(String.valueOf(insets.bottom));
+ }
+ addVerifyListeners(this.right);
+
+ }
+
+ /**
+ * Fill property.
+ *
+ * @param item the item
+ * @param property the property
+ * @see org.mihalis.opal.propertyTable.editor.PTWindowEditor#fillProperty(org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void fillProperty(final Item item, final PTProperty property) {
+ final Insets i = new Insets(getIntValue(this.top), getIntValue(this.left), getIntValue(this.bottom), getIntValue(this.right));
+ property.setValue(i);
+ if (item instanceof TableItem) {
+ ((TableItem) item).setText(1, getTextFor(property));
+ } else {
+ ((TreeItem) item).setText(1, getTextFor(property));
+ }
+ }
+
+ /**
+ * Gets the text for.
+ *
+ * @param property the property
+ * @return the text for
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getTextFor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected String getTextFor(final PTProperty property) {
+ if (property.getValue() == null) {
+ return "(null)";
+ }
+ final Insets insets = (Insets) property.getValue();
+ return "[" + insets.top + "," + insets.left + "," + insets.bottom + "," + insets.right + "]";
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTIntegerEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTIntegerEditor.java
new file mode 100644
index 0000000..a29c014
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTIntegerEditor.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+/**
+ * This editor is used to edit integer values.
+ */
+public class PTIntegerEditor extends PTBaseTextEditor {
+
+ /**
+ * Adds the verify listeners.
+ *
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#addVerifyListeners()
+ */
+ @Override
+ public void addVerifyListeners() {
+ this.text.addListener(SWT.Verify, new Listener() {
+ @Override
+ public void handleEvent(final Event e) {
+ final String string = e.text;
+ final char[] chars = new char[string.length()];
+ string.getChars(0, chars.length, chars, 0);
+ for (int i = 0; i < chars.length; i++) {
+ if (!('0' <= chars[i] && chars[i] <= '9') && e.keyCode != SWT.BS && e.keyCode != SWT.DEL) {
+ e.doit = false;
+ return;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Convert value.
+ *
+ * @return the object
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#convertValue()
+ */
+ @Override
+ public Object convertValue() {
+ int ret = 0;
+ try {
+ ret = Integer.parseInt(this.text.getText());
+ } catch (final NumberFormatException e) {
+ ret = 0;
+ this.text.setText("0");
+ }
+ return ret;
+ }
+
+ /**
+ * Gets the style.
+ *
+ * @return the style
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#getStyle()
+ */
+ @Override
+ public int getStyle() {
+ return SWT.NONE;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTPasswordEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTPasswordEditor.java
new file mode 100644
index 0000000..fc78991
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTPasswordEditor.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+
+/**
+ * This editor is used to edit passwords.
+ */
+public class PTPasswordEditor extends PTBaseTextEditor {
+
+ /**
+ * Adds the verify listeners.
+ *
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#addVerifyListeners()
+ */
+ @Override
+ public void addVerifyListeners() {
+ }
+
+ /**
+ * Convert value.
+ *
+ * @return the object
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#convertValue()
+ */
+ @Override
+ public Object convertValue() {
+ return this.text.getText();
+ }
+
+ /**
+ * Gets the style.
+ *
+ * @return the style
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#getStyle()
+ */
+ @Override
+ public int getStyle() {
+ return SWT.PASSWORD;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTRectangleEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTRectangleEditor.java
new file mode 100644
index 0000000..8e67dbc
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTRectangleEditor.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * Editor for {@link Rectangle} property.
+ */
+public class PTRectangleEditor extends PTWindowEditor {
+
+ /** The x. */
+ private Text x;
+
+ /** The y. */
+ private Text y;
+
+ /** The width. */
+ private Text width;
+
+ /** The height. */
+ private Text height;
+
+ /**
+ * Creates the content.
+ *
+ * @param shell the shell
+ * @param property the property
+ * @see org.mihalis.opal.propertyTable.editor.PTWindowEditor#createContent(org.eclipse.swt.widgets.Shell,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void createContent(final Shell shell, final PTProperty property) {
+ final Label xLabel = new Label(shell, SWT.NONE);
+ xLabel.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+ xLabel.setText("X");
+
+ this.x = new Text(shell, SWT.BORDER);
+ this.x.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ if (property.getValue() != null) {
+ final Rectangle rect = (Rectangle) property.getValue();
+ this.x.setText(String.valueOf(rect.x));
+ }
+ addVerifyListeners(this.x);
+
+ final Label yLabel = new Label(shell, SWT.NONE);
+ yLabel.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+ yLabel.setText("Y");
+
+ this.y = new Text(shell, SWT.BORDER);
+ this.y.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ if (property.getValue() != null) {
+ final Rectangle rect = (Rectangle) property.getValue();
+ this.y.setText(String.valueOf(rect.y));
+ }
+ addVerifyListeners(this.y);
+
+ final Label widthLabel = new Label(shell, SWT.NONE);
+ widthLabel.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+ widthLabel.setText(ResourceManager.getLabel(ResourceManager.WIDTH));
+
+ this.width = new Text(shell, SWT.BORDER);
+ this.width.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ if (property.getValue() != null) {
+ final Rectangle rect = (Rectangle) property.getValue();
+ this.x.setText(String.valueOf(rect.width));
+ }
+ addVerifyListeners(this.width);
+
+ final Label heightLabel = new Label(shell, SWT.NONE);
+ heightLabel.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+ heightLabel.setText(ResourceManager.getLabel(ResourceManager.HEIGHT));
+
+ this.height = new Text(shell, SWT.BORDER);
+ this.height.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ if (property.getValue() != null) {
+ final Rectangle rect = (Rectangle) property.getValue();
+ this.y.setText(String.valueOf(rect.height));
+ }
+ addVerifyListeners(this.height);
+
+ }
+
+ /**
+ * Fill property.
+ *
+ * @param item the item
+ * @param property the property
+ * @see org.mihalis.opal.propertyTable.editor.PTWindowEditor#fillProperty(org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void fillProperty(final Item item, final PTProperty property) {
+ final Rectangle r = new Rectangle(getIntValue(this.x), getIntValue(this.y), getIntValue(this.width), getIntValue(this.height));
+ property.setValue(r);
+ if (item instanceof TableItem) {
+ ((TableItem) item).setText(1, getTextFor(property));
+ } else {
+ ((TreeItem) item).setText(1, getTextFor(property));
+ }
+ }
+
+ /**
+ * Gets the text for.
+ *
+ * @param property the property
+ * @return the text for
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getTextFor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected String getTextFor(final PTProperty property) {
+ if (property.getValue() == null) {
+ return "(null)";
+ }
+ final Rectangle rect = (Rectangle) property.getValue();
+ return "[" + rect.x + "," + rect.y + "," + rect.width + "," + rect.height + "]";
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTSpinnerEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTSpinnerEditor.java
new file mode 100644
index 0000000..48aa494
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTSpinnerEditor.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ControlEditor;
+import org.eclipse.swt.custom.TableEditor;
+import org.eclipse.swt.custom.TreeEditor;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Spinner;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+
+/**
+ * This editor is a spinner.
+ */
+public class PTSpinnerEditor extends PTEditor {
+
+ /** The max. */
+ private final int max;
+
+ /** The min. */
+ private final int min;
+
+ /**
+ * Constructor.
+ *
+ * @param min minimum value
+ * @param max maximum value
+ */
+ public PTSpinnerEditor(final int min, final int max) {
+ this.min = min;
+ this.max = max;
+ }
+
+ /**
+ * Render.
+ *
+ * @param widget the widget
+ * @param item the item
+ * @param property the property
+ * @return the control editor
+ * @see org.mihalis.opal.propertyTable.editor.PTEditor#render(org.mihalis.opal.propertyTable.PTWidget,
+ * org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ public ControlEditor render(final PTWidget widget, final Item item, final PTProperty property) {
+ ControlEditor editor;
+ if (widget.getWidget() instanceof Table) {
+ editor = new TableEditor((Table) widget.getWidget());
+ } else {
+ editor = new TreeEditor((Tree) widget.getWidget());
+ }
+
+ final Spinner spinner = new Spinner(widget.getWidget(), SWT.HORIZONTAL);
+
+ spinner.setMinimum(this.min);
+ spinner.setMaximum(this.max);
+ final Integer originalValue = (Integer) property.getValue();
+ spinner.setSelection(originalValue == null ? this.min : originalValue.intValue());
+
+ spinner.addListener(SWT.FocusIn, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ widget.updateDescriptionPanel(property);
+ }
+ });
+
+ spinner.addListener(SWT.Modify, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ property.setValue(Integer.valueOf(spinner.getSelection()));
+ }
+ });
+
+ editor.grabHorizontal = true;
+ if (widget.getWidget() instanceof Table) {
+ ((TableEditor) editor).setEditor(spinner, (TableItem) item, 1);
+ } else {
+ ((TreeEditor) editor).setEditor(spinner, (TreeItem) item, 1);
+ }
+
+ spinner.setEnabled(property.isEnabled());
+
+ return editor;
+
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTStringEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTStringEditor.java
new file mode 100644
index 0000000..9eb0ba1
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTStringEditor.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+
+/**
+ * This editor is used to edit string values.
+ */
+public class PTStringEditor extends PTBaseTextEditor {
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#addVerifyListeners()
+ */
+ @Override
+ public void addVerifyListeners() {
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#convertValue()
+ */
+ @Override
+ public Object convertValue() {
+ return this.text.getText();
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#getStyle()
+ */
+ @Override
+ public int getStyle() {
+ return SWT.NONE;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTURLEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTURLEditor.java
new file mode 100644
index 0000000..ee616e9
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTURLEditor.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.mihalis.opal.opalDialog.Dialog;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * This editor is used to edit URL values.
+ */
+public class PTURLEditor extends PTBaseTextEditor {
+
+ /**
+ * Adds the verify listeners.
+ *
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#addVerifyListeners()
+ */
+ @Override
+ public void addVerifyListeners() {
+ this.text.addListener(SWT.FocusOut, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ try {
+ new URL(PTURLEditor.this.text.getText()); // NOSONAR
+ } catch (final MalformedURLException e) {
+ Dialog.error(ResourceManager.getLabel(ResourceManager.APPLICATION_ERROR), ResourceManager.getLabel(ResourceManager.VALID_URL));
+ event.doit = false;
+ PTURLEditor.this.text.forceFocus();
+ }
+
+ }
+ });
+
+ }
+
+ /**
+ * Convert value.
+ *
+ * @return the object
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#convertValue()
+ */
+ @Override
+ public Object convertValue() {
+ return this.text.getText();
+ }
+
+ /**
+ * Gets the style.
+ *
+ * @return the style
+ * @see org.mihalis.opal.propertyTable.editor.PTBaseTextEditor#getStyle()
+ */
+ @Override
+ public int getStyle() {
+ return SWT.NONE;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTWindowEditor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTWindowEditor.java
new file mode 100644
index 0000000..676b380
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/propertyTable/editor/PTWindowEditor.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * 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.propertyTable.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+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.Event;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.propertyTable.PTProperty;
+import org.mihalis.opal.propertyTable.PTWidget;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This abstract class contains common code for editors that open a window :
+ * dimension editor, insets editor, rectangle editor.
+ */
+public abstract class PTWindowEditor extends PTChooserEditor {
+
+ /**
+ * Open window.
+ *
+ * @param widget the widget
+ * @param item the item
+ * @param property the property
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#openWindow(org.mihalis.opal.propertyTable.PTWidget,
+ * org.eclipse.swt.widgets.Item,
+ * org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected void openWindow(final PTWidget widget, final Item item, final PTProperty property) {
+ final Shell shell = new Shell(widget.getWidget().getShell(), SWT.DIALOG_TRIM);
+ shell.setLayout(new GridLayout(2, false));
+ shell.setText(ResourceManager.getLabel(ResourceManager.EDIT_PROPERTY));
+
+ final Label title = new Label(shell, SWT.NONE);
+ final GridData titleLayoutData = new GridData(GridData.BEGINNING, GridData.BEGINNING, true, false, 2, 1);
+ titleLayoutData.widthHint = 400;
+ title.setLayoutData(titleLayoutData);
+ final Font font = SWTGraphicUtil.buildFontFrom(title, SWT.BOLD, 16);
+ title.setFont(font);
+ title.setText(ResourceManager.getLabel(ResourceManager.EDIT_PROPERTY));
+ SWTGraphicUtil.addDisposer(title, font);
+
+ createContent(shell, property);
+
+ final Composite composite = new Composite(shell, SWT.NONE);
+ composite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false, 2, 1));
+
+ final GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
+ composite.setLayout(gridLayout);
+
+ final Button ok = new Button(composite, SWT.PUSH);
+ final GridData okLayoutData = new GridData(GridData.END, GridData.BEGINNING, true, false);
+ okLayoutData.widthHint = 150;
+ ok.setLayoutData(okLayoutData);
+ ok.setText(ResourceManager.getLabel(ResourceManager.OK));
+ ok.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ fillProperty(item, property);
+ shell.dispose();
+ }
+ });
+
+ final Button cancel = new Button(composite, SWT.PUSH);
+ final GridData cancelLayoutData = new GridData(GridData.END, GridData.BEGINNING, false, false);
+ cancelLayoutData.widthHint = 150;
+ cancel.setLayoutData(cancelLayoutData);
+ cancel.setText(ResourceManager.getLabel(ResourceManager.CANCEL));
+ cancel.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ shell.dispose();
+ }
+ });
+
+ shell.setDefaultButton(ok);
+ shell.pack();
+ SWTGraphicUtil.centerShell(shell);
+ shell.open();
+ }
+
+ /**
+ * Fill property when the ok button is pressed.
+ *
+ * @param item item in which the string representation of property's value
+ * is display
+ * @param property associated property
+ */
+ protected abstract void fillProperty(Item item, PTProperty property);
+
+ /**
+ * Create the content (text widgets).
+ *
+ * @param shell associated shell
+ * @param property associated property
+ */
+ protected abstract void createContent(Shell shell, PTProperty property);
+
+ /**
+ * Gets the background color.
+ *
+ * @param property the property
+ * @return the background color
+ * @see org.mihalis.opal.propertyTable.editor.PTChooserEditor#getBackgroundColor(org.mihalis.opal.propertyTable.PTProperty)
+ */
+ @Override
+ protected Color getBackgroundColor(final PTProperty property) {
+ return null;
+ }
+
+ /**
+ * Gets the int value.
+ *
+ * @param text text widget
+ * @return the integer value stored in a text. If the text value is empty,
+ * returns 0
+ */
+ protected int getIntValue(final Text text) {
+ if (text.getText().trim().equals("")) {
+ return 0;
+ }
+ return Integer.parseInt(text.getText().trim());
+ }
+
+ /**
+ * Add a verify listener to a given text that accepts only integers.
+ *
+ * @param text text widget
+ */
+ protected void addVerifyListeners(final Text text) {
+ text.addListener(SWT.Verify, new Listener() {
+ @Override
+ public void handleEvent(final Event e) {
+ final String string = e.text;
+ final char[] chars = new char[string.length()];
+ string.getChars(0, chars.length, chars, 0);
+ for (int i = 0; i < chars.length; i++) {
+ if (!('0' <= chars[i] && chars[i] <= '9') && e.keyCode != SWT.BS && e.keyCode != SWT.DEL) {
+ e.doit = false;
+ return;
+ }
+ }
+ }
+ });
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/rangeSlider/RangeSlider.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/rangeSlider/RangeSlider.java
new file mode 100644
index 0000000..0c8283e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/rangeSlider/RangeSlider.java
@@ -0,0 +1,1140 @@
+/*******************************************************************************
+ * 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.rangeSlider;
+
+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.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 provide a slider with 2 buttons (min value, max
+ * value).
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER</dd>
+ * <dd>HORIZONTAL</dd>
+ * <dd>VERTICAL</dd> *
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * </p>
+ */
+public class RangeSlider extends Canvas {
+
+ /**
+ * The Enum SELECTED_KNOB.
+ */
+ private enum SELECTED_KNOB {
+
+ /** The none. */
+ NONE,
+ /** The upper. */
+ UPPER,
+ /** The lower. */
+ LOWER
+ };
+
+ /** The minimum. */
+ private int minimum;
+
+ /** The maximum. */
+ private int maximum;
+
+ /** The lower value. */
+ private int lowerValue;
+
+ /** The upper value. */
+ private int upperValue;
+
+ /** The listeners. */
+ private final List<SelectionListener> listeners;
+
+ /** The slider selected. */
+ private final Image slider, sliderHover, sliderDrag, sliderSelected;
+
+ /** The v slider selected. */
+ private final Image vSlider, vSliderHover, vSliderDrag, vSliderSelected;
+
+ /** The orientation. */
+ private int orientation;
+
+ /** The increment. */
+ private int increment;
+
+ /** The page increment. */
+ private int pageIncrement;
+
+ /** The last selected. */
+ private SELECTED_KNOB lastSelected;
+
+ /** The drag in progress. */
+ private boolean dragInProgress;
+
+ /** The coord upper. */
+ private Point coordUpper;
+
+ /** The upper hover. */
+ private boolean upperHover;
+
+ /** The coord lower. */
+ private Point coordLower;
+
+ /** The lower hover. */
+ private boolean lowerHover;
+
+ /** The previous upper value. */
+ private int previousUpperValue;
+
+ /** The previous lower value. */
+ private int previousLowerValue;
+
+ /**
+ * 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 RangeSlider(final Composite parent, final int style) {
+ super(parent, SWT.DOUBLE_BUFFERED | ((style & SWT.BORDER) == SWT.BORDER ? SWT.BORDER : SWT.NONE));
+ minimum = lowerValue = 0;
+ maximum = upperValue = 100;
+ listeners = new ArrayList<SelectionListener>();
+ increment = 1;
+ pageIncrement = 10;
+ lastSelected = SELECTED_KNOB.NONE;
+ final ClassLoader loader = org.mihalis.opal.rangeSlider.RangeSlider.class.getClassLoader();
+ slider = new Image(getDisplay(), loader.getResourceAsStream("images/slider-normal.png"));
+ sliderHover = new Image(getDisplay(), loader.getResourceAsStream("images/slider-hover.png"));
+ sliderDrag = new Image(getDisplay(), loader.getResourceAsStream("images/slider-drag.png"));
+ sliderSelected = new Image(getDisplay(), loader.getResourceAsStream("images/slider-selected.png"));
+
+ vSlider = new Image(getDisplay(), loader.getResourceAsStream("images/h-slider-normal.png"));
+ vSliderHover = new Image(getDisplay(), loader.getResourceAsStream("images/h-slider-hover.png"));
+ vSliderDrag = new Image(getDisplay(), loader.getResourceAsStream("images/h-slider-drag.png"));
+ vSliderSelected = new Image(getDisplay(), loader.getResourceAsStream("images/h-slider-selected.png"));
+
+ if ((style & SWT.VERTICAL) == SWT.VERTICAL) {
+ orientation = SWT.VERTICAL;
+ } else {
+ orientation = SWT.HORIZONTAL;
+ }
+
+ addListener(SWT.Dispose, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ SWTGraphicUtil.safeDispose(slider);
+ SWTGraphicUtil.safeDispose(sliderHover);
+ SWTGraphicUtil.safeDispose(sliderDrag);
+ SWTGraphicUtil.safeDispose(sliderSelected);
+
+ SWTGraphicUtil.safeDispose(vSlider);
+ SWTGraphicUtil.safeDispose(vSliderHover);
+ SWTGraphicUtil.safeDispose(vSliderDrag);
+ SWTGraphicUtil.safeDispose(vSliderSelected);
+
+ }
+ });
+
+ addMouseListeners();
+ addListener(SWT.KeyDown, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ handleKeyDown(event);
+ }
+ });
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(final PaintEvent e) {
+ drawWidget(e);
+
+ }
+ });
+
+ }
+
+ /**
+ * Add the mouse listeners (mouse up, mouse down, mouse move, mouse wheel).
+ */
+ private void addMouseListeners() {
+ addListener(SWT.MouseDown, new Listener() {
+ @Override
+ public void handleEvent(final Event e) {
+ handleMouseDown(e);
+ }
+ });
+
+ addListener(SWT.MouseUp, new Listener() {
+ @Override
+ public void handleEvent(final Event e) {
+ handleMouseUp(e);
+ }
+ });
+
+ addListener(SWT.MouseMove, new Listener() {
+ @Override
+ public void handleEvent(final Event e) {
+ handleMouseMove(e);
+ }
+ });
+
+ addListener(SWT.MouseWheel, new Listener() {
+ @Override
+ public void handleEvent(final Event e) {
+ handleMouseWheel(e);
+ }
+ });
+
+ }
+
+ /**
+ * Code executed when the mouse is down.
+ *
+ * @param e event
+ */
+ private void handleMouseDown(final Event e) {
+
+ if (upperHover) {
+ dragInProgress = true;
+ lastSelected = SELECTED_KNOB.UPPER;
+ previousUpperValue = upperValue;
+ return;
+ }
+
+ if (lowerHover) {
+ dragInProgress = true;
+ lastSelected = SELECTED_KNOB.LOWER;
+ previousLowerValue = lowerValue;
+ return;
+ }
+
+ dragInProgress = false;
+ lastSelected = SELECTED_KNOB.NONE;
+ }
+
+ /**
+ * Code executed when the mouse is up.
+ *
+ * @param e event
+ */
+ private void handleMouseUp(final Event e) {
+ if (!dragInProgress) {
+ return;
+ }
+ dragInProgress = false;
+ if (!fireSelectionListeners(e)) {
+ if (lastSelected == SELECTED_KNOB.UPPER) {
+ upperValue = previousUpperValue;
+ } else {
+ lowerValue = previousLowerValue;
+ }
+ redraw();
+ }
+ }
+
+ /**
+ * Fire all selection listeners.
+ *
+ * @param event selection event
+ * @return <code>true</code> if no listener cancels the selection,
+ * <code>false</code> otherwise
+ */
+ private boolean fireSelectionListeners(final Event event) {
+ for (final SelectionListener selectionListener : listeners) {
+ final SelectionEvent selectionEvent = new SelectionEvent(event);
+ selectionListener.widgetSelected(selectionEvent);
+ if (!selectionEvent.doit) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Code executed when the mouse pointer is moving.
+ *
+ * @param e event
+ */
+ private void handleMouseMove(final Event e) {
+ final int x = e.x, y = e.y;
+ final Image img = orientation == SWT.HORIZONTAL ? slider : vSlider;
+ upperHover = x >= coordUpper.x && x <= coordUpper.x + img.getBounds().width && y >= coordUpper.y && y <= coordUpper.y + img.getBounds().height;
+ lowerHover = x >= coordLower.x && x <= coordLower.x + img.getBounds().width && y >= coordLower.y && y <= coordLower.y + img.getBounds().height;
+
+ if (dragInProgress) {
+ final int mouseValue;
+
+ if (orientation == SWT.HORIZONTAL) {
+ mouseValue = (int) ((x - 9f) / computePixelSizeForHorizonalSlider()) + minimum;
+ } else {
+ mouseValue = (int) ((y - 9f) / computePixelSizeForVerticalSlider()) + minimum;
+ }
+ final int refValue = (int) (Math.ceil(mouseValue / (double) increment) * increment) - increment;
+
+ if (lastSelected == SELECTED_KNOB.UPPER) {
+ upperValue = refValue;
+ checkUpperValue();
+ } else {
+ lowerValue = refValue;
+ checkLowerValue();
+ }
+
+// if (orientation == SWT.HORIZONTAL) {
+// final int mouseValue = (int) ((x - 9f) / computePixelSizeForHorizonalSlider()) + minimum;
+//
+// if (lastSelected == SELECTED_KNOB.UPPER) {
+// upperValue = (int) (Math.ceil(mouseValue / increment) * increment) - increment;
+// checkUpperValue();
+// } else {
+// lowerValue = (int) (Math.ceil(mouseValue / increment) * increment) - increment;
+// checkLowerValue();
+// }
+//
+// } else {
+// final int mouseValue = (int) ((y - 9f) / computePixelSizeForVerticalSlider()) + minimum;
+//
+// if (lastSelected == SELECTED_KNOB.UPPER) {
+// upperValue = (int) (Math.ceil(mouseValue / increment) * increment) - increment;
+// checkUpperValue();
+// } else {
+// lowerValue = (int) (Math.ceil(mouseValue / increment) * increment) - increment;
+// checkLowerValue();
+// }
+//
+// }
+ }
+
+ redraw();
+ }
+
+ /**
+ * Code executed when the mouse wheel is activated.
+ *
+ * @param e event
+ */
+ private void handleMouseWheel(final Event e) {
+ if (lastSelected == SELECTED_KNOB.NONE) {
+ return;
+ }
+
+ if (lastSelected == SELECTED_KNOB.LOWER) {
+ lowerValue += e.count * increment;
+ checkLowerValue();
+ redraw();
+ } else {
+ upperValue += e.count * increment;
+ checkUpperValue();
+ redraw();
+ }
+ }
+
+ /**
+ * Check if the lower value is in ranges.
+ */
+ private void checkLowerValue() {
+ if (lowerValue < minimum) {
+ lowerValue = minimum;
+ }
+ if (lowerValue > maximum) {
+ lowerValue = maximum;
+ }
+ if (lowerValue > upperValue) {
+ lowerValue = upperValue;
+ }
+ }
+
+ /**
+ * Check if the upper value is in ranges.
+ */
+ private void checkUpperValue() {
+ if (upperValue < minimum) {
+ upperValue = minimum;
+ }
+ if (upperValue > maximum) {
+ upperValue = maximum;
+ }
+ if (upperValue < lowerValue) {
+ upperValue = lowerValue;
+ }
+ }
+
+ /**
+ * Draws the widget.
+ *
+ * @param e paint event
+ */
+ private void drawWidget(final PaintEvent e) {
+ final Rectangle rect = getClientArea();
+ if (rect.width == 0 || rect.height == 0) {
+ return;
+ }
+ e.gc.setAdvanced(true);
+ e.gc.setAntialias(SWT.ON);
+ if (orientation == SWT.HORIZONTAL) {
+ drawHorizontalRangeSlider(e.gc);
+ } else {
+ drawVerticalRangeSlider(e.gc);
+ }
+
+ }
+
+ /**
+ * Draw the range slider (horizontal).
+ *
+ * @param gc graphic context
+ */
+ private void drawHorizontalRangeSlider(final GC gc) {
+ drawBackgroundHorizontal(gc);
+ drawBarsHorizontal(gc);
+ coordUpper = drawHorizontalKnob(gc, upperValue, true);
+ coordLower = drawHorizontalKnob(gc, lowerValue, false);
+ }
+
+ /**
+ * Draw the background.
+ *
+ * @param gc graphic context
+ */
+ private void drawBackgroundHorizontal(final GC gc) {
+ final Rectangle clientArea = getClientArea();
+
+ gc.setBackground(getBackground());
+ gc.fillRectangle(clientArea);
+
+ if (isEnabled()) {
+ gc.setForeground(getForeground());
+ } else {
+ gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_GRAY));
+ }
+ gc.drawRoundRectangle(9, 9, clientArea.width - 20, clientArea.height - 20, 3, 3);
+
+ final float pixelSize = computePixelSizeForHorizonalSlider();
+ final int startX = (int) (pixelSize * lowerValue);
+ final int endX = (int) (pixelSize * upperValue);
+ if (isEnabled()) {
+ gc.setBackground(getForeground());
+ } else {
+ gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_GRAY));
+ }
+ gc.fillRectangle(12 + startX, 9, endX - startX - 6, clientArea.height - 20);
+
+ }
+
+ /**
+ * Compute pixel size for horizonal slider.
+ *
+ * @return how many pixels corresponds to 1 point of value
+ */
+ private float computePixelSizeForHorizonalSlider() {
+ return (getClientArea().width - 20f) / (maximum - minimum);
+ }
+
+ /**
+ * Draw the bars.
+ *
+ * @param gc graphic context
+ */
+ private void drawBarsHorizontal(final GC gc) {
+ final Rectangle clientArea = getClientArea();
+ if (isEnabled()) {
+ gc.setForeground(getForeground());
+ } else {
+ gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_GRAY));
+ }
+
+ final float pixelSize = computePixelSizeForHorizonalSlider();
+ for (int i = 1; i < 10; i++) {
+ final int x = (int) (9 + pixelSize * (maximum - minimum) / 10 * i);
+ gc.drawLine(x, 4, x, 7);
+ gc.drawLine(x, clientArea.height - 6, x, clientArea.height - 9);
+ }
+
+ }
+
+ /**
+ * Draws an horizontal knob.
+ *
+ * @param gc graphic context
+ * @param value corresponding value
+ * @param upper if <code>true</code>, draws the upper knob. If
+ * <code>false</code>, draws the lower knob
+ * @return the coordinate of the upper left corner of the knob
+ */
+ private Point drawHorizontalKnob(final GC gc, final int value, final boolean upper) {
+ final float pixelSize = computePixelSizeForHorizonalSlider();
+ final int x = (int) (pixelSize * value);
+ Image image;
+ if (upper) {
+ if (upperHover) {
+ image = dragInProgress ? sliderDrag : sliderHover;
+ } else if (lastSelected == SELECTED_KNOB.UPPER) {
+ image = sliderSelected;
+ } else {
+ image = slider;
+ }
+ } else {
+ if (lowerHover) {
+ image = dragInProgress ? sliderDrag : sliderHover;
+ } else if (lastSelected == SELECTED_KNOB.LOWER) {
+ image = sliderSelected;
+ } else {
+ image = slider;
+ }
+ }
+ if (isEnabled()) {
+ gc.drawImage(image, x + 5, getClientArea().height / 2 - slider.getBounds().height / 2);
+ } else {
+ final Image temp = new Image(getDisplay(), image, SWT.IMAGE_DISABLE);
+ gc.drawImage(temp, x + 5, getClientArea().height / 2 - slider.getBounds().height / 2);
+ temp.dispose();
+ }
+ return new Point(x + 5, getClientArea().height / 2 - slider.getBounds().height / 2);
+ }
+
+ /**
+ * Draw the range slider (vertical).
+ *
+ * @param gc graphic context
+ */
+ private void drawVerticalRangeSlider(final GC gc) {
+ drawBackgroundVertical(gc);
+ drawBarsVertical(gc);
+ coordUpper = drawVerticalKnob(gc, upperValue, true);
+ coordLower = drawVerticalKnob(gc, lowerValue, false);
+ }
+
+ /**
+ * Draws the background.
+ *
+ * @param gc graphic context
+ */
+ private void drawBackgroundVertical(final GC gc) {
+ final Rectangle clientArea = getClientArea();
+ gc.setBackground(getBackground());
+ gc.fillRectangle(clientArea);
+
+ if (isEnabled()) {
+ gc.setForeground(getForeground());
+ } else {
+ gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_GRAY));
+ }
+ gc.drawRoundRectangle(9, 9, clientArea.width - 20, clientArea.height - 20, 3, 3);
+
+ final float pixelSize = computePixelSizeForVerticalSlider();
+ final int startY = (int) (pixelSize * lowerValue);
+ final int endY = (int) (pixelSize * upperValue);
+ if (isEnabled()) {
+ gc.setBackground(getForeground());
+ } else {
+ gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_GRAY));
+ }
+ gc.fillRectangle(9, 12 + startY, clientArea.width - 20, endY - startY - 6);
+
+ }
+
+ /**
+ * Compute pixel size for vertical slider.
+ *
+ * @return how many pixels corresponds to 1 point of value
+ */
+ private float computePixelSizeForVerticalSlider() {
+ return (getClientArea().height - 20f) / (maximum - minimum);
+ }
+
+ /**
+ * Draws the bars.
+ *
+ * @param gc graphic context
+ */
+ private void drawBarsVertical(final GC gc) {
+ final Rectangle clientArea = getClientArea();
+ if (isEnabled()) {
+ gc.setForeground(getForeground());
+ } else {
+ gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_GRAY));
+ }
+
+ final float pixelSize = computePixelSizeForVerticalSlider();
+ for (int i = 1; i < 10; i++) {
+ final int y = (int) (9 + pixelSize * (maximum - minimum) / 10 * i);
+ gc.drawLine(4, y, 7, y);
+ gc.drawLine(clientArea.width - 6, y, clientArea.width - 9, y);
+
+ }
+
+ }
+
+ /**
+ * Draws a vertical knob.
+ *
+ * @param gc graphic context
+ * @param value corresponding value
+ * @param upper if <code>true</code>, draws the upper knob. If
+ * <code>false</code>, draws the lower knob
+ * @return the coordinate of the upper left corner of the knob
+ */
+ private Point drawVerticalKnob(final GC gc, final int value, final boolean upper) {
+ final float pixelSize = computePixelSizeForVerticalSlider();
+ final int y = (int) (pixelSize * value);
+
+ Image image;
+ if (upper) {
+ if (upperHover) {
+ image = dragInProgress ? vSliderDrag : vSliderHover;
+ } else if (lastSelected == SELECTED_KNOB.UPPER) {
+ image = vSliderSelected;
+ } else {
+ image = vSlider;
+ }
+ } else {
+ if (lowerHover) {
+ image = dragInProgress ? vSliderDrag : vSliderHover;
+ } else if (lastSelected == SELECTED_KNOB.LOWER) {
+ image = vSliderSelected;
+ } else {
+ image = vSlider;
+ }
+ }
+
+ if (isEnabled()) {
+ gc.drawImage(image, getClientArea().width / 2 - 8, y + 2);
+ } else {
+ final Image temp = new Image(getDisplay(), image, SWT.IMAGE_DISABLE);
+ gc.drawImage(temp, getClientArea().width / 2 - 8, y + 2);
+ temp.dispose();
+ }
+ return new Point(getClientArea().width / 2 - 8, y + 2);
+ }
+
+ /**
+ * Code executed when a key is typed.
+ *
+ * @param event event
+ */
+ private void handleKeyDown(final Event event) {
+
+ boolean needRedraw = false;
+
+ if (lastSelected == SELECTED_KNOB.NONE) {
+ lastSelected = SELECTED_KNOB.LOWER;
+ }
+
+ switch (event.keyCode) {
+ case SWT.HOME:
+ if (lastSelected == SELECTED_KNOB.UPPER) {
+ upperValue = minimum;
+ } else {
+ lowerValue = minimum;
+ }
+ needRedraw = true;
+ break;
+ case SWT.END:
+ if (lastSelected == SELECTED_KNOB.UPPER) {
+ upperValue = maximum;
+ } else {
+ lowerValue = maximum;
+ }
+ needRedraw = true;
+ break;
+ case SWT.PAGE_UP:
+ if (lastSelected == SELECTED_KNOB.UPPER) {
+ upperValue += pageIncrement;
+ } else {
+ lowerValue += pageIncrement;
+ }
+ needRedraw = true;
+ break;
+ case SWT.PAGE_DOWN:
+ if (lastSelected == SELECTED_KNOB.UPPER) {
+ upperValue -= pageIncrement;
+ } else {
+ lowerValue -= pageIncrement;
+ }
+ needRedraw = true;
+ break;
+ case SWT.ARROW_LEFT:
+ case SWT.ARROW_UP:
+ if (lastSelected == SELECTED_KNOB.UPPER) {
+ upperValue -= increment;
+ } else {
+ lowerValue -= increment;
+ }
+ needRedraw = true;
+ break;
+ case SWT.ARROW_RIGHT:
+ case SWT.ARROW_DOWN:
+ if (lastSelected == SELECTED_KNOB.UPPER) {
+ upperValue += increment;
+ } else {
+ lowerValue += increment;
+ }
+ needRedraw = true;
+ break;
+ }
+
+ if (needRedraw) {
+ if (lastSelected == SELECTED_KNOB.UPPER) {
+ checkUpperValue();
+ } else {
+ checkLowerValue();
+ }
+ redraw();
+ }
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified
+ * when the user changes the receiver's value, by sending it one of the
+ * messages defined in the <code>SelectionListener</code> interface.
+ * <p>
+ * <code>widgetSelected</code> is called when the user changes the
+ * receiver's value. <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @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();
+ 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) {
+ final int width, height;
+ checkWidget();
+ if (orientation == SWT.HORIZONTAL) {
+ if (wHint < 100) {
+ width = 100;
+ } else {
+ width = wHint;
+ }
+
+ if (hHint < 30) {
+ height = 30;
+ } else {
+ height = hHint;
+ }
+ } else {
+ if (wHint < 30) {
+ width = 30;
+ } else {
+ width = wHint;
+ }
+
+ if (hHint < 100) {
+ height = 100;
+ } else {
+ height = hHint;
+ }
+ }
+
+ return new Point(width, height);
+ }
+
+ /**
+ * Returns the amount that the selected receiver's value will be modified by
+ * when the up/down (or right/left) 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() {
+ checkWidget();
+ return increment;
+ }
+
+ /**
+ * Returns the 'lower selection', which is the lower 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 getLowerValue() {
+ checkWidget();
+ return lowerValue;
+ }
+
+ /**
+ * 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() {
+ checkWidget();
+ return 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() {
+ checkWidget();
+ return minimum;
+ }
+
+ /**
+ * Returns the amount that the selected receiver's value will be modified by
+ * when the page increment/decrement areas are selected.
+ *
+ * @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() {
+ checkWidget();
+ return pageIncrement;
+ }
+
+ /**
+ * Returns the 'selection', which is an array where the first element is the
+ * lower selection, and the second element is the upper selection.
+ *
+ * @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() {
+ checkWidget();
+ final int[] selection = new int[2];
+ selection[0] = lowerValue;
+ selection[1] = upperValue;
+ return selection;
+ }
+
+ /**
+ * Returns the 'upper selection', which is the upper 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 getUpperValue() {
+ checkWidget();
+ return upperValue;
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be
+ * notified when the user changes the receiver's value.
+ *
+ * @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();
+ listeners.remove(listener);
+ }
+
+ /**
+ * Sets the amount that the selected receiver's value will be modified by
+ * when the up/down (or right/left) arrows are pressed to the argument,
+ * which must be at least one.
+ *
+ * @param increment 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 increment) {
+ checkWidget();
+ this.increment = increment;
+ redraw();
+ }
+
+ /**
+ * Sets the 'lower selection', which is the receiver's lower value, to the
+ * argument which must be greater than or equal to zero.
+ *
+ * @param value the new selection (must be zero or greater)
+ *
+ * @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 setLowerValue(final int value) {
+ checkWidget();
+ if (minimum <= value && value <= maximum && value <= upperValue) {
+ lowerValue = value;
+ }
+ redraw();
+ }
+
+ /**
+ * Sets the maximum value that the receiver will allow. This new value will
+ * be ignored if it is not greater 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 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) {
+ checkWidget();
+ if (minimum <= value) {
+ maximum = value;
+ if (lowerValue >= maximum) {
+ lowerValue = maximum;
+ }
+ if (upperValue >= maximum) {
+ upperValue = maximum;
+ }
+ }
+ redraw();
+ }
+
+ /**
+ * Sets the minimum value that the receiver will allow. This new value will
+ * be ignored if it is negative or is not less 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 nonnegative and less than 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) {
+ checkWidget();
+ if (maximum >= value) {
+ minimum = value;
+ if (lowerValue <= minimum) {
+ lowerValue = minimum;
+ }
+ if (upperValue <= minimum) {
+ upperValue = minimum;
+ }
+ }
+ redraw();
+ }
+
+ /**
+ * Sets the amount that the receiver's value will be modified by when the
+ * page increment/decrement areas are selected to the argument, which must
+ * be at least one.
+ *
+ * @param pageIncrement 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 pageIncrement) {
+ checkWidget();
+ this.pageIncrement = pageIncrement;
+ }
+
+ /**
+ * Sets the 'selection', which is the receiver's value, to the argument
+ * which must be greater than or equal to zero.
+ *
+ * @param values 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(final int[] values) {
+ checkWidget();
+ setLowerValue(values[0]);
+ setUpperValue(values[1]);
+ checkUpperValue();
+ checkLowerValue();
+ redraw();
+ }
+
+ /**
+ * Sets the 'selection', which is the receiver's value, argument which must
+ * be greater than or equal to zero.
+ *
+ * @param lowerValue the new lower selection (must be zero or greater)
+ * @param upperValue the new upper selection (must be zero or greater)
+ *
+ * @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 int lowerValue, final int upperValue) {
+ checkWidget();
+ setLowerValue(lowerValue);
+ setUpperValue(upperValue);
+ }
+
+ /**
+ * Sets the 'upper selection', which is the upper receiver's value, argument
+ * which must be greater than or equal to zero.
+ *
+ * @param value the new selection (must be zero or greater)
+ *
+ * @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 setUpperValue(final int value) {
+ checkWidget();
+ if (minimum <= value && value <= maximum && value >= lowerValue) {
+ upperValue = value;
+ }
+ redraw();
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/roundedToolbar/RoundedToolItem.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/roundedToolbar/RoundedToolItem.java
new file mode 100644
index 0000000..535e65b
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/roundedToolbar/RoundedToolItem.java
@@ -0,0 +1,1005 @@
+/*******************************************************************************
+ * 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.roundedToolbar;
+
+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.AdvancedPath;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class represent a selectable user interface object that
+ * represents a button in a rounded tool bar.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#toolbar">ToolBar, ToolItem
+ * snippets</a>
+ */
+public class RoundedToolItem extends Item {
+
+ /** The Constant MARGIN. */
+ private static final int MARGIN = 4;
+
+ /** The start gradient color. */
+ private static Color START_GRADIENT_COLOR = SWTGraphicUtil.getColorSafely(70, 70, 70);
+
+ /** The end gradient color. */
+ private static Color END_GRADIENT_COLOR = SWTGraphicUtil.getColorSafely(116, 116, 116);
+
+ /** The parent toolbar. */
+ private final RoundedToolbar parentToolbar;
+
+ /** 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 vertical alignment. */
+ private int verticalAlignment;
+
+ /** 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. */
+ private boolean isLast;
+
+ /**
+ * Constructs a new instance of this class given its parent (which must be a
+ * <code>ToolBar</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 RoundedToolItem(final RoundedToolbar parent) {
+ this(parent, SWT.NONE);
+ }
+
+ /**
+ * Constructs a new instance of this class given its parent (which must be a
+ * <code>ToolBar</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 RoundedToolItem(final RoundedToolbar parent, final int style) {
+ super(parent, style);
+ parent.addItem(this);
+ parentToolbar = parent;
+ textColor = parent.getDisplay().getSystemColor(SWT.COLOR_BLACK);
+ textColorSelected = parent.getDisplay().getSystemColor(SWT.COLOR_WHITE);
+ enabled = true;
+ alignment = SWT.CENTER;
+ verticalAlignment = SWT.CENTER;
+ selectionListeners = new ArrayList<SelectionListener>();
+ width = -1;
+ height = -1;
+ }
+
+ /**
+ * 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);
+ }
+ selectionListeners.add(listener);
+ }
+
+ /**
+ * Compute default size.
+ *
+ * @return the default size of the item
+ */
+ Point computeDefaultSize() {
+ final Point sizeOfTextAndImages = computeSizeOfTextAndImages();
+ return new Point(2 * MARGIN + sizeOfTextAndImages.x, 2 * MARGIN + sizeOfTextAndImages.y);
+ }
+
+ /**
+ * Compute size of text and images.
+ *
+ * @return the point
+ */
+ private Point computeSizeOfTextAndImages() {
+ int width = 0, height = 0;
+ final boolean textNotEmpty = getText() != null && !getText().equals("");
+
+ if (textNotEmpty) {
+ final GC gc = new GC(parentToolbar);
+ final Point extent = gc.stringExtent(getText());
+ gc.dispose();
+ width += extent.x;
+ height = extent.y;
+ }
+
+ final Point imageSize = new Point(-1, -1);
+ computeImageSize(getImage(), imageSize);
+ computeImageSize(selectionImage, imageSize);
+ computeImageSize(disabledImage, imageSize);
+
+ if (imageSize.x != -1) {
+ width += imageSize.x;
+ height = Math.max(imageSize.y, height);
+ if (textNotEmpty) {
+ width += MARGIN;
+ }
+ }
+ return new Point(width, height);
+ }
+
+ /**
+ * Compute image size.
+ *
+ * @param image the image
+ * @param imageSize the image size
+ */
+ private void computeImageSize(final Image image, final Point imageSize) {
+ if (image == null) {
+ return;
+ }
+ final Rectangle imageBounds = image.getBounds();
+ imageSize.x = Math.max(imageBounds.width, imageSize.x);
+ imageSize.y = Math.max(imageBounds.height, imageSize.y);
+ }
+
+ /**
+ * Dispose.
+ *
+ * @see org.eclipse.swt.widgets.Widget#dispose()
+ */
+ @Override
+ public void dispose() {
+ selectionListeners.clear();
+ getParent().removeItem(this);
+ bounds = null;
+ disabledImage = null;
+ selectionImage = null;
+ textColor = null;
+ textColorSelected = null;
+ super.dispose();
+ }
+
+ /**
+ * Draw button.
+ *
+ * @param gc the gc
+ * @param x the x
+ * @param toolbarHeight the toolbar height
+ * @param isLast the is last
+ */
+ void drawButton(final GC gc, final int x, final int toolbarHeight, final boolean isLast) {
+ this.gc = gc;
+ this.toolbarHeight = toolbarHeight;
+ this.isLast = isLast;
+
+ if (selection) {
+ drawBackground(x);
+ }
+ if (!isLast) {
+ drawRightLine(x);
+ }
+
+ int xPosition = computeHorizontalPosition(x);
+
+ xPosition += drawImage(x + xPosition);
+ drawText(x + xPosition);
+
+ bounds = new Rectangle(x, 0, getWidth(), toolbarHeight);
+ }
+
+ /**
+ * Draw background.
+ *
+ * @param x the x
+ */
+ private void drawBackground(final int x) {
+ final AdvancedPath path = new AdvancedPath(getDisplay());
+ final boolean isFirst = getParent().indexOf(this) == 0;
+ if (isFirst) {
+ path.addRoundRectangleStraightRight(x, 0, getWidth(), toolbarHeight, parentToolbar.getCornerRadius(), parentToolbar.getCornerRadius());
+ } else if (isLast) {
+ path.addRoundRectangleStraightLeft(x, 0, getWidth(), toolbarHeight, parentToolbar.getCornerRadius(), parentToolbar.getCornerRadius());
+ } else {
+ path.addRectangle(x, 0, getWidth(), toolbarHeight);
+ }
+
+ gc.setClipping(path);
+
+ gc.setForeground(START_GRADIENT_COLOR);
+ gc.setBackground(END_GRADIENT_COLOR);
+ gc.fillGradientRectangle(x, 0, getWidth() + parentToolbar.getCornerRadius(), toolbarHeight, true);
+
+ gc.setClipping((Rectangle) null);
+ }
+
+ /**
+ * Draw right line.
+ *
+ * @param x the x
+ */
+ private void drawRightLine(final int x) {
+ gc.setForeground(RoundedToolbar.BORDER_COLOR);
+ gc.drawLine(x + getWidth(), 0, x + getWidth(), toolbarHeight);
+ }
+
+ /**
+ * Compute horizontal position.
+ *
+ * @param x the x
+ * @return the int
+ */
+ private int computeHorizontalPosition(final int x) {
+ final int widthOfTextAndImage = computeSizeOfTextAndImages().x;
+ switch (alignment) {
+ case SWT.CENTER:
+ return (getWidth() - widthOfTextAndImage) / 2;
+ case SWT.RIGHT:
+ return getWidth() - widthOfTextAndImage - MARGIN;
+ default:
+ return MARGIN;
+ }
+ }
+
+ /**
+ * Compute vertical position.
+ *
+ * @param height the height
+ * @return the int
+ */
+ private int computeVerticalPosition(final int height) {
+ switch (verticalAlignment) {
+ case SWT.CENTER:
+ return (toolbarHeight - height) / 2;
+ case SWT.TOP:
+ return MARGIN;
+ default:
+ return toolbarHeight - height - MARGIN;
+ }
+ }
+
+ /**
+ * Fire selection event.
+ */
+ void fireSelectionEvent() {
+ final Event event = new Event();
+ event.widget = parentToolbar;
+ event.display = getDisplay();
+ event.item = this;
+ event.type = SWT.Selection;
+ for (final SelectionListener selectionListener : selectionListeners) {
+ selectionListener.widgetSelected(new SelectionEvent(event));
+ }
+ }
+
+ /**
+ * Draw image.
+ *
+ * @param xPosition the x position
+ * @return the int
+ */
+ private int drawImage(final int xPosition) {
+ Image image;
+ if (!isEnabled()) {
+ image = disabledImage;
+ } else if (selection) {
+ image = selectionImage;
+ } else {
+ image = getImage();
+ }
+
+ if (image == null) {
+ return 0;
+ }
+
+ final int yPosition = computeVerticalPosition(image.getBounds().height);
+ gc.drawImage(image, xPosition, yPosition);
+ return image.getBounds().width + MARGIN;
+ }
+
+ /**
+ * Draw text.
+ *
+ * @param xPosition the x position
+ */
+ private void drawText(final int xPosition) {
+ gc.setFont(parentToolbar.getFont());
+ if (selection) {
+ gc.setForeground(textColorSelected);
+ } else {
+ gc.setForeground(textColor);
+ }
+
+ final Point textSize = gc.stringExtent(getText());
+ final int yPosition = computeVerticalPosition(textSize.y);
+
+ gc.drawText(getText(), xPosition, yPosition, true);
+ }
+
+ /**
+ * 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 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 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 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 enabled;
+ }
+
+ /**
+ * Returns the whole height of the widget.
+ *
+ * @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 (height == -1) {
+ return computeDefaultSize().y;
+ }
+ return height;
+ }
+
+ /**
+ * Returns the receiver's parent, which must be a
+ * <code>RoundedToolBar</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 RoundedToolbar getParent() {
+ checkWidget();
+ return parentToolbar;
+ }
+
+ /**
+ * 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 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 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 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 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 tooltipText;
+ }
+
+ /**
+ * Returns a value which describes the position of the text in the receiver.
+ * The value will be one of <code>TOP</code>, <code>BOTTOM</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 getVerticalAlignment() {
+ checkWidget();
+ return verticalAlignment;
+ }
+
+ /**
+ * Returns the whole height of the widget.
+ *
+ * @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 (width == -1) {
+ return computeDefaultSize().x;
+ }
+ return 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 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);
+ }
+ 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 (bounds == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+
+ 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();
+ 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();
+ 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();
+ 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();
+ 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();
+ tooltipText = string == null ? "" : string;
+ }
+
+ /**
+ * Controls how text will be displayed in the receiver. The argument should
+ * be one of <code>TOP</code>, <code>BOTTOM</code> or <code>CENTER</code>.
+ *
+ * @param verticalAlignment the new vertical 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 setVerticalAlignment(final int verticalAlignment) {
+ checkWidget();
+ this.verticalAlignment = verticalAlignment;
+ }
+
+ /**
+ * 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);
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/roundedToolbar/RoundedToolbar.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/roundedToolbar/RoundedToolbar.java
new file mode 100644
index 0000000..8f5379b
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/roundedToolbar/RoundedToolbar.java
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * 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.roundedToolbar;
+
+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.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.eclipse.swt.widgets.Widget;
+import org.mihalis.opal.utils.AdvancedPath;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class support the layout of selectable
+ * rounded tool bar items.
+ * <p>
+ * The item children that may be added to instances of this class
+ * must be of type <code>RoundedToolItem</code>.
+ * </p>
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>NONE</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#toolbar">ToolBar, ToolItem snippets</a>
+ */
+public class RoundedToolbar extends Canvas {
+
+ /** The items. */
+ private final List<RoundedToolItem> items;
+
+ /** The multi selection. */
+ private boolean multiSelection;
+
+ /** The corner radius. */
+ private int cornerRadius;
+
+ /** The start gradient color default. */
+ private static Color START_GRADIENT_COLOR_DEFAULT = SWTGraphicUtil.getColorSafely(245, 245, 245);
+
+ /** The end gradient color default. */
+ private static Color END_GRADIENT_COLOR_DEFAULT = SWTGraphicUtil.getColorSafely(185, 185, 185);
+
+ /** The border color. */
+ static Color BORDER_COLOR = SWTGraphicUtil.getColorSafely(66, 66, 66);
+
+ /** The start gradient color. */
+ private Color START_GRADIENT_COLOR = START_GRADIENT_COLOR_DEFAULT;
+
+ /** The end gradient color. */
+ private Color END_GRADIENT_COLOR = END_GRADIENT_COLOR_DEFAULT;
+
+
+ /**
+ * 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 RoundedToolbar(final Composite parent, final int style) {
+ super(parent, style | SWT.DOUBLE_BUFFERED);
+ items = new ArrayList<RoundedToolItem>();
+ cornerRadius = 2;
+ addListeners();
+ }
+
+ /**
+ * Constructs a new instance of this class given its parent, a style value
+ * describing its behavior and appearance and colors to specify the start
+ * and end gradient of the rounded corner
+ * <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 startGradientColor the start gradient color
+ * @param endGradientColor the end gradient color
+ * @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 RoundedToolbar(final Composite parent, final int style,Color startGradientColor,Color endGradientColor) {
+ super(parent, style | SWT.DOUBLE_BUFFERED);
+ items = new ArrayList<RoundedToolItem>();
+ cornerRadius = 2;
+ addListeners();
+ START_GRADIENT_COLOR=startGradientColor;
+ END_GRADIENT_COLOR=endGradientColor;
+ }
+
+ /**
+ * Adds the listeners.
+ */
+ private void addListeners() {
+ addListener(SWT.MouseUp, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ for (final RoundedToolItem item : items) {
+ if (item.getBounds().contains(event.x, event.y)) {
+ if (!multiSelection) {
+ applyRadioBehaviour(item);
+ }
+ item.setSelection(!item.getSelection());
+ item.fireSelectionEvent();
+ redraw();
+ update();
+ return;
+ }
+ }
+ }
+
+ private void applyRadioBehaviour(final RoundedToolItem selectedItem) {
+ for (final RoundedToolItem item : items) {
+ if (!item.equals(selectedItem)) {
+ item.setSelection(false);
+ item.fireSelectionEvent();
+ }
+ }
+ }
+ });
+
+ addListener(SWT.MouseHover, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ for (final RoundedToolItem item : items) {
+ if (item.getBounds().contains(event.x, event.y)) {
+ setToolTipText(item.getTooltipText() == null ? "" : item.getTooltipText());
+ return;
+ }
+ }
+ }
+ });
+
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(final PaintEvent e) {
+ RoundedToolbar.this.paintControl(e);
+ }
+ });
+ }
+
+ /**
+ * Add an item to the toolbar.
+ *
+ * @param roundedToolItem roundedToolItem to add
+ */
+ void addItem(final RoundedToolItem roundedToolItem) {
+ items.add(roundedToolItem);
+ }
+
+ /**
+ * 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;
+ for (final RoundedToolItem item : items) {
+ width += item.getWidth();
+ height = Math.max(height, item.getHeight());
+ }
+ return new Point(Math.max(width, wHint), Math.max(height, hHint));
+ }
+
+ /**
+ * Gets the corner radius.
+ *
+ * @return the corner radius
+ */
+ public int getCornerRadius() {
+ checkWidget();
+ return this.cornerRadius;
+ }
+
+ /**
+ * 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 RoundedToolItem getItem(final int index) {
+ checkWidget();
+ if (index < 0 || index > items.size()) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ return 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 RoundedToolItem getItem(final Point point) {
+ checkWidget();
+ for (final RoundedToolItem item : 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 items.size();
+ }
+
+ /**
+ * Returns an array of <code>RoundedToolItem</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 RoundedToolItem[] getItems() {
+ checkWidget();
+ return items.toArray(new RoundedToolItem[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 tool item is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the tool 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 RoundedToolItem item) {
+ checkWidget();
+ return items.indexOf(item);
+ }
+
+ /**
+ * Checks if is multiselection.
+ *
+ * @return <code>true</code> if the toolbar is in multiselection mode,
+ * <code>false</code> otherwise
+ */
+ public boolean isMultiselection() {
+ checkWidget();
+ return this.multiSelection;
+ }
+
+ /**
+ * Paint the component.
+ *
+ * @param e event
+ */
+ protected 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;
+
+ drawBorders(gc, width, height);
+ final Iterator<RoundedToolItem> it = items.iterator();
+ int x = 0;
+ while (it.hasNext()) {
+ final RoundedToolItem item = it.next();
+ item.drawButton(gc, x, height, !it.hasNext());
+ x += item.getWidth();
+ }
+ }
+
+ /**
+ * Draw borders.
+ *
+ * @param gc the gc
+ * @param width the width
+ * @param height the height
+ */
+ private void drawBorders(final GC gc, final int width, final int height) {
+ final AdvancedPath path = new AdvancedPath(getDisplay());
+ path.addRoundRectangle(0, 0, width, height, cornerRadius, cornerRadius);
+ gc.setClipping(path);
+
+ gc.setForeground(START_GRADIENT_COLOR);
+ gc.setBackground(END_GRADIENT_COLOR);
+ gc.fillGradientRectangle(0, 0, width, height, true);
+
+ gc.setForeground(BORDER_COLOR);
+ gc.drawRoundRectangle(0, 0, width - 1, height - 1, cornerRadius, cornerRadius);
+
+ gc.setClipping((Rectangle) null);
+ }
+
+ /**
+ * Add an item to the toolbar.
+ *
+ * @param roundedToolItem roundedToolItem to add
+ */
+ void removeItem(final RoundedToolItem roundedToolItem) {
+ checkWidget();
+ items.remove(roundedToolItem);
+ }
+
+ /**
+ * Sets the corner radius.
+ *
+ * @param cornerRadius new corner radius
+ */
+ public void setCornerRadius(final int cornerRadius) {
+ checkWidget();
+ this.cornerRadius = cornerRadius;
+ }
+
+ /**
+ * Sets the multiselection.
+ *
+ * @param multiSelection new value of the multi selection flag
+ */
+ public void setMultiselection(final boolean multiSelection) {
+ checkWidget();
+ this.multiSelection = multiSelection;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/starRating/Star.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/starRating/Star.java
new file mode 100644
index 0000000..914c015
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/starRating/Star.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * 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@gmail.com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.starRating;
+
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Instances of this class represent a star displayed by the StarRating
+ * component.
+ */
+class Star {
+
+ /** The Constant SMALL_STAR_MARKED_FOCUS. */
+ private static final String SMALL_STAR_MARKED_FOCUS = "mark-focus16.png";
+
+ /** The Constant SMALL_STAR_MARKED. */
+ private static final String SMALL_STAR_MARKED = "mark16.png";
+
+ /** The Constant SMALL_STAR_FOCUS. */
+ private static final String SMALL_STAR_FOCUS = "focus16.png";
+
+ /** The Constant SMALL_STAR. */
+ private static final String SMALL_STAR = "16.png";
+
+ /** The Constant BIG_STAR_MARKED_FOCUS. */
+ private static final String BIG_STAR_MARKED_FOCUS = "mark-focus32.png";
+
+ /** The Constant BIG_STAR_MARKED. */
+ private static final String BIG_STAR_MARKED = "mark32.png";
+
+ /** The Constant BIG_STAR_FOCUS. */
+ private static final String BIG_STAR_FOCUS = "focus32.png";
+
+ /** The Constant BIG_STAR. */
+ private static final String BIG_STAR = "32.png";
+
+ /** The hover. */
+ boolean hover;
+
+ /** The marked. */
+ boolean marked;
+
+ /** The bounds. */
+ Rectangle bounds;
+
+ /** The default image. */
+ Image defaultImage;
+
+ /** The hover image. */
+ Image hoverImage;
+
+ /** The selected image. */
+ Image selectedImage;
+
+ /** The selected hover image. */
+ Image selectedHoverImage;
+
+ /** The parent. */
+ private StarRating parent;
+
+ /**
+ * Dispose.
+ */
+ void dispose() {
+ defaultImage.dispose();
+ hoverImage.dispose();
+ selectedImage.dispose();
+ selectedHoverImage.dispose();
+ }
+
+ /**
+ * Draw.
+ *
+ * @param gc the gc
+ * @param x the x
+ * @param y the y
+ */
+ void draw(final GC gc, final int x, final int y) {
+ Image image;
+ if (!parent.isEnabled()) {
+ image = defaultImage;
+ } else {
+ if (marked) {
+ if (hover) {
+ image = selectedHoverImage;
+ } else {
+ image = selectedImage;
+ }
+ } else {
+ if (hover) {
+ image = hoverImage;
+ } else {
+ image = defaultImage;
+ }
+ }
+ }
+
+ gc.drawImage(image, x, y);
+ bounds = new Rectangle(x, y, image.getBounds().width, image.getBounds().height);
+ }
+
+ /**
+ * Inits the big.
+ *
+ * @param parent the parent
+ * @return the star
+ */
+ static Star initBig(final StarRating parent) {
+ final Star star = new Star();
+ star.parent = parent;
+ final ClassLoader loader = org.mihalis.opal.starRating.Star.class.getClassLoader();
+ star.defaultImage = new Image(Display.getCurrent(), loader.getResourceAsStream("images/stars/" + BIG_STAR));
+ star.hoverImage = new Image(Display.getCurrent(), loader.getResourceAsStream("images/stars/" + BIG_STAR_FOCUS));
+ star.selectedImage = new Image(Display.getCurrent(), loader.getResourceAsStream("images/stars/" + BIG_STAR_MARKED));
+ star.selectedHoverImage = new Image(Display.getCurrent(), loader.getResourceAsStream("images/stars/" + BIG_STAR_MARKED_FOCUS));
+ return star;
+ }
+
+ /**
+ * Inits the small.
+ *
+ * @param parent the parent
+ * @return the star
+ */
+ static Star initSmall(final StarRating parent) {
+ final Star star = new Star();
+ star.parent = parent;
+ final ClassLoader loader = org.mihalis.opal.starRating.Star.class.getClassLoader();
+ star.defaultImage = new Image(Display.getCurrent(), loader.getResourceAsStream("images/stars/" + SMALL_STAR));
+ star.hoverImage = new Image(Display.getCurrent(), loader.getResourceAsStream("images/stars/" + SMALL_STAR_FOCUS));
+ star.selectedImage = new Image(Display.getCurrent(), loader.getResourceAsStream("images/stars/" + SMALL_STAR_MARKED));
+ star.selectedHoverImage = new Image(Display.getCurrent(), loader.getResourceAsStream("images/stars/" + SMALL_STAR_MARKED_FOCUS));
+ return star;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/starRating/StarRating.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/starRating/StarRating.java
new file mode 100644
index 0000000..dfbf171
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/starRating/StarRating.java
@@ -0,0 +1,514 @@
+/*******************************************************************************
+ * 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@gmail.com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.starRating;
+
+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.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;
+
+/**
+ * Instances of this class provide a rating element.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>HORIZONTAL</dd>
+ * <dd>VERTICAL</dd> *
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ * </p>
+ */
+public class StarRating extends Canvas {
+
+ /** The Constant SIZE_SMALL. */
+ private static final int SIZE_SMALL = 16;
+
+ /** The Constant SIZE_BIG. */
+ private static final int SIZE_BIG = 32;
+
+ /**
+ * The Enum SIZE.
+ */
+ public enum SIZE {
+
+ /** The small. */
+ SMALL,
+ /** The big. */
+ BIG
+ };
+
+ /** The size of stars. */
+ private SIZE sizeOfStars;
+
+ /** The max number of stars. */
+ private int maxNumberOfStars;
+
+ /** The current number of stars. */
+ private int currentNumberOfStars;
+
+ /** The Constant DEFAULT_MAX_NUMBERS_OF_STARS. */
+ private static final int DEFAULT_MAX_NUMBERS_OF_STARS = 5;
+
+ /** The stars. */
+ private final List<Star> stars;
+
+ /** The orientation. */
+ private int orientation;
+
+ /** 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 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 StarRating(final Composite parent, final int style) {
+ super(parent, checkStyle(style) | SWT.DOUBLE_BUFFERED);
+ sizeOfStars = SIZE.SMALL;
+ currentNumberOfStars = 0;
+
+ if ((style & SWT.VERTICAL) != 0) {
+ orientation = SWT.VERTICAL;
+ } else {
+ orientation = SWT.HORIZONTAL;
+ }
+
+ stars = new ArrayList<Star>();
+ selectionListeners = new ArrayList<SelectionListener>();
+ setMaxNumberOfStars(DEFAULT_MAX_NUMBERS_OF_STARS);
+ initListeners();
+ }
+
+ /**
+ * Check style.
+ *
+ * @param style the style
+ * @return the int
+ */
+ private static int checkStyle(int style) {
+ if ((style & SWT.VERTICAL) != 0) {
+ style = style & ~SWT.VERTICAL;
+ }
+
+ if ((style & SWT.HORIZONTAL) != 0) {
+ style = style & ~SWT.HORIZONTAL;
+ }
+ return style;
+ }
+
+ /**
+ * Inits the listeners.
+ */
+ private void initListeners() {
+ final Listener listener = new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ switch (event.type) {
+ case SWT.MouseEnter:
+ case SWT.MouseMove:
+ onMouseEnterOrMove(event);
+ break;
+ case SWT.MouseExit:
+ onMouseExit(event);
+ break;
+ case SWT.MouseUp:
+ onMouseUp(event);
+ break;
+ case SWT.Paint:
+ onMousePaint(event);
+ break;
+ case SWT.Dispose:
+ onDispose(event);
+ break;
+ }
+ }
+ };
+
+ final int[] events = new int[] { SWT.MouseEnter, SWT.MouseMove, SWT.MouseExit, SWT.MouseUp, SWT.Paint, SWT.Dispose };
+ for (final int event : events) {
+ addListener(event, listener);
+ }
+ }
+
+ /**
+ * On mouse enter or move.
+ *
+ * @param event the event
+ */
+ private void onMouseEnterOrMove(final Event event) {
+ for (final Star star : stars) {
+ star.hover = false;
+ }
+
+ for (final Star star : stars) {
+ final boolean mouseHover = star.bounds.contains(event.x, event.y);
+ star.hover = true;
+ if (mouseHover) {
+ break;
+ }
+ }
+ redraw();
+ update();
+ }
+
+ /**
+ * On mouse exit.
+ *
+ * @param event the event
+ */
+ private void onMouseExit(final Event event) {
+ for (final Star star : stars) {
+ star.hover = false;
+ }
+ redraw();
+ update();
+ }
+
+ /**
+ * On mouse up.
+ *
+ * @param event the event
+ */
+ private void onMouseUp(final Event event) {
+ for (int i = 0; i < maxNumberOfStars; i++) {
+ final Star star = stars.get(i);
+ final boolean selected = star.bounds.contains(event.x, event.y);
+ if (selected) {
+ setCurrentNumberOfStars(i + 1);
+ fireSelectionEvent();
+ redraw();
+ update();
+ break;
+ }
+ }
+
+ }
+
+ /**
+ * Fire selection event.
+ */
+ private void fireSelectionEvent() {
+ final Event event = new Event();
+ event.widget = this;
+ event.display = getDisplay();
+ event.item = this;
+ event.type = SWT.Selection;
+ for (final SelectionListener selectionListener : selectionListeners) {
+ selectionListener.widgetSelected(new SelectionEvent(event));
+ }
+ }
+
+ /**
+ * On mouse paint.
+ *
+ * @param event the event
+ */
+ private void onMousePaint(final Event event) {
+ final GC gc = event.gc;
+ int x = 0, y = 0;
+
+ for (final Star star : stars) {
+ star.draw(gc, x, y);
+ if (orientation == SWT.VERTICAL) {
+ y += sizeOfStars.equals(SIZE.BIG) ? SIZE_BIG : SIZE_SMALL;
+ } else {
+ x += sizeOfStars.equals(SIZE.BIG) ? SIZE_BIG : SIZE_SMALL;
+ }
+ }
+ }
+
+ /**
+ * On dispose.
+ *
+ * @param event the event
+ */
+ private void onDispose(final Event event) {
+ for (final Star star : stars) {
+ star.dispose();
+ }
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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) {
+ if (orientation == SWT.VERTICAL) {
+ return computeSizeVertical();
+ }
+ return computeSizeHorizontal();
+ }
+
+ /**
+ * Compute size vertical.
+ *
+ * @return the point
+ */
+ private Point computeSizeVertical() {
+ final int width = sizeOfStars.equals(SIZE.BIG) ? SIZE_BIG : SIZE_SMALL;
+ final int height = maxNumberOfStars * width;
+ return new Point(width + getBorderWidth() * 2, height + getBorderWidth() * 2);
+ }
+
+ /**
+ * Compute size horizontal.
+ *
+ * @return the point
+ */
+ private Point computeSizeHorizontal() {
+ final int height = sizeOfStars.equals(SIZE.BIG) ? SIZE_BIG : SIZE_SMALL;
+ final int width = maxNumberOfStars * height;
+ return new Point(width + getBorderWidth() * 2, height + getBorderWidth() * 2);
+ }
+
+ /**
+ * Gets the current number of stars.
+ *
+ * @return the number of selected stars
+ * @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 getCurrentNumberOfStars() {
+ checkWidget();
+ return currentNumberOfStars;
+ }
+
+ /**
+ * Gets the max number of stars.
+ *
+ * @return the maximum number of stars that is displayed by this component
+ * @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 getMaxNumberOfStars() {
+ checkWidget();
+ return maxNumberOfStars;
+ }
+
+ /**
+ * Gets the orientation.
+ *
+ * @return the orientation of this widget (SWT.VERTICAL or SWT.HORIZONTAL)
+ * @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 getOrientation() {
+ checkWidget();
+ return orientation;
+ }
+
+ /**
+ * Gets the size of stars.
+ *
+ * @return the size of stars
+ * @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 SIZE getSizeOfStars() {
+ checkWidget();
+ return sizeOfStars;
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Set the current number of stars.
+ *
+ * @param currentNumberOfStars current number of stars
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the number of star is
+ * negative or greater than the maximum number of stars</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 setCurrentNumberOfStars(final int currentNumberOfStars) {
+ checkWidget();
+ if (currentNumberOfStars < 0 || currentNumberOfStars > maxNumberOfStars) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.currentNumberOfStars = currentNumberOfStars;
+ for (final Star star : stars) {
+ star.marked = false;
+ }
+
+ for (int i = 0; i < currentNumberOfStars; i++) {
+ stars.get(i).marked = true;
+ }
+ }
+
+ /**
+ * Set the maximum number of stars.
+ *
+ * @param maxNumberOfStars the new max number of stars
+ * @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 setMaxNumberOfStars(final int maxNumberOfStars) {
+ this.maxNumberOfStars = maxNumberOfStars;
+ reinitStars();
+ }
+
+ /**
+ * Reinit stars.
+ */
+ private void reinitStars() {
+ for (final Star star : stars) {
+ star.dispose();
+ }
+ stars.clear();
+ for (int i = 0; i < maxNumberOfStars; i++) {
+ if (sizeOfStars.equals(SIZE.BIG)) {
+ stars.add(Star.initBig(this));
+ } else {
+ stars.add(Star.initSmall(this));
+ }
+ }
+
+ }
+
+ /**
+ * Set the current size of stars.
+ *
+ * @param sizeOfStars current number of stars
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the number of star is
+ * negative or greater than the maximum number of stars</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 setSizeOfStars(final SIZE sizeOfStars) {
+ checkWidget();
+ this.sizeOfStars = sizeOfStars;
+ reinitStars();
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/switchButton/SwitchButton.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/switchButton/SwitchButton.java
new file mode 100644
index 0000000..d29bf56
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/switchButton/SwitchButton.java
@@ -0,0 +1,878 @@
+/*******************************************************************************
+ * 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.switchButton;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseTrackListener;
+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.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.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are simple switch button.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Selection</dd>
+ * </dl>
+ */
+public class SwitchButton extends Canvas {
+
+ /** Selection. */
+ private boolean selection;
+
+ /** Text displayed for the selected value (default = "On"). */
+ private String textForSelect;
+
+ /** Text displayed for the unselected value (default = "Off"). */
+ private String textForUnselect;
+
+ /** Text corresponding to the button (default is ""). */
+ private String text;
+
+ /**
+ * If true, display round rectangles instead of rectangles (default value is
+ * true).
+ */
+ private boolean round;
+
+ /**
+ * if not null, displays a rectangle (or a round rectangle) around the whole
+ * widget. Default value is null.
+ */
+ private Color borderColor;
+
+ /**
+ * if not null, displays a glow effect when the mouse is over the widget.
+ * Default value is null.
+ */
+ private Color focusColor;
+
+ /** Colors when the button is selected. */
+ private Color selectedForegroundColor, selectedBackgroundColor;
+
+ /** Colors when the button is not selected. */
+ private Color unselectedForegroundColor, unselectedBackgroundColor;
+
+ /** Colors for the button. */
+ private Color buttonBorderColor, buttonBackgroundColor1, buttonBackgroundColor2;
+
+ /** Gap between the button and the text (default value is 5). */
+ private int gap = 5;
+
+ /** Margin inside the button (default is 5). */
+ private int insideMarginX = 5;
+
+ /** Margin inside the button (default is 5). */
+ private int insideMarginY = 5;
+
+ /** Arc of rounded rectangles (default is 3). */
+ private int arc = 3;
+
+ /** Graphical context for this button. */
+ private GC gc;
+
+ /** List of selection listeners. */
+ private final List<SelectionListener> listOfSelectionListeners;
+
+ /** True when the mouse entered the widget. */
+ private boolean mouseInside;
+
+ /**
+ * 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 SwitchButton(final Composite parent, final int style) {
+ super(parent, style | SWT.DOUBLE_BUFFERED);
+
+ selection = false;
+ text = "";
+ textForSelect = "On";
+ textForUnselect = "Off";
+ round = true;
+ borderColor = null;
+ focusColor = getDisplay().getSystemColor(SWT.COLOR_YELLOW);
+ selectedForegroundColor = getDisplay().getSystemColor(SWT.COLOR_WHITE);
+ selectedBackgroundColor = SWTGraphicUtil.getDefaultColor(this, 0, 112, 195);
+ unselectedForegroundColor = getDisplay().getSystemColor(SWT.COLOR_BLACK);
+ unselectedBackgroundColor = SWTGraphicUtil.getDefaultColor(this, 203, 203, 203);
+ buttonBorderColor = SWTGraphicUtil.getDefaultColor(this, 96, 96, 96);
+ buttonBackgroundColor1 = SWTGraphicUtil.getDefaultColor(this, 254, 254, 254);
+ buttonBackgroundColor2 = SWTGraphicUtil.getDefaultColor(this, 192, 192, 192);
+
+ listOfSelectionListeners = new ArrayList<SelectionListener>();
+
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(final PaintEvent event) {
+ SwitchButton.this.onPaint(event);
+ }
+ });
+
+ addMouseListener(new MouseAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.MouseAdapter#mouseUp(org.eclipse.swt.events.MouseEvent)
+ */
+ @Override
+ public void mouseUp(final MouseEvent e) {
+ if (SwitchButton.this.fireSelectionListeners(e)) {
+ selection = !selection;
+ SwitchButton.this.redraw();
+
+ // notify listeners that were registered via
+ // Widget#addListener
+ SwitchButton.this.notifyListeners(SWT.Selection, new Event());
+
+ }
+ }
+
+ });
+
+ mouseInside = false;
+ addMouseTrackListener(new MouseTrackListener() {
+
+ @Override
+ public void mouseHover(final MouseEvent e) {
+ mouseInside = true;
+ SwitchButton.this.redraw();
+ }
+
+ @Override
+ public void mouseExit(final MouseEvent e) {
+ mouseInside = false;
+ SwitchButton.this.redraw();
+ }
+
+ @Override
+ public void mouseEnter(final MouseEvent e) {
+ mouseInside = true;
+ SwitchButton.this.redraw();
+ }
+ });
+
+ }
+
+ /**
+ * Paint the widget.
+ *
+ * @param event paint event
+ */
+ private void onPaint(final PaintEvent event) {
+ final Rectangle rect = getClientArea();
+ if (rect.width == 0 || rect.height == 0) {
+ return;
+ }
+ gc = event.gc;
+ gc.setAntialias(SWT.ON);
+
+ final Point buttonSize = computeButtonSize();
+ drawSwitchButton(buttonSize);
+ drawText(buttonSize);
+
+ if (borderColor != null) {
+ drawBorder();
+ }
+
+ }
+
+ /**
+ * Draw the switch button.
+ *
+ * @param buttonSize size of the button
+ */
+ private void drawSwitchButton(final Point buttonSize) {
+ // Draw the background of the button
+ gc.setForeground(buttonBorderColor);
+ if (round) {
+ gc.drawRoundRectangle(2, 2, buttonSize.x, buttonSize.y, arc, arc);
+ } else {
+ gc.drawRectangle(2, 2, buttonSize.x, buttonSize.y);
+ }
+
+ drawRightPart(buttonSize);
+ drawLeftPart(buttonSize);
+ gc.setClipping(getClientArea());
+ drawToggleButton(buttonSize);
+ }
+
+ /**
+ * Draw the right part of the button.
+ *
+ * @param buttonSize size of the button
+ */
+ private void drawRightPart(final Point buttonSize) {
+ gc.setForeground(selectedBackgroundColor);
+ gc.setBackground(selectedBackgroundColor);
+ gc.setClipping(3, 3, buttonSize.x / 2, buttonSize.y - 1);
+ if (round) {
+ gc.fillRoundRectangle(2, 2, buttonSize.x, buttonSize.y, arc, arc);
+ } else {
+ gc.fillRectangle(2, 2, buttonSize.x, buttonSize.y);
+ }
+ gc.setForeground(selectedForegroundColor);
+ final Point textSize = gc.textExtent(textForSelect);
+ gc.drawString(textForSelect, (buttonSize.x / 2 - textSize.x) / 2 + arc, (buttonSize.y - textSize.y) / 2 + arc);
+ }
+
+ /**
+ * Draw the left part of the button.
+ *
+ * @param buttonSize size of the button
+ */
+ private void drawLeftPart(final Point buttonSize) {
+ gc.setForeground(unselectedBackgroundColor);
+ gc.setBackground(unselectedBackgroundColor);
+ gc.setClipping(buttonSize.x / 2 + 3, 3, buttonSize.x / 2, buttonSize.y - 1);
+ if (round) {
+ gc.fillRoundRectangle(2, 2, buttonSize.x, buttonSize.y, arc, arc);
+ } else {
+ gc.fillRectangle(2, 2, buttonSize.x, buttonSize.y);
+ }
+ gc.setForeground(unselectedForegroundColor);
+ final Point textSize = gc.textExtent(textForUnselect);
+
+ gc.drawString(textForUnselect, buttonSize.x / 2 + (buttonSize.x / 2 - textSize.x) / 2 + arc, //
+ (buttonSize.y - textSize.y) / 2 + arc);
+ }
+
+ /**
+ * Draw the toggle button.
+ *
+ * @param buttonSize size of the button
+ */
+ private void drawToggleButton(final Point buttonSize) {
+ gc.setForeground(buttonBackgroundColor1);
+ gc.setBackground(buttonBackgroundColor2);
+ if (selection) {
+ gc.fillGradientRectangle(arc, arc, buttonSize.x / 2, buttonSize.y, true);
+ } else {
+ gc.fillGradientRectangle(buttonSize.x / 2, arc, buttonSize.x / 2 + 2, buttonSize.y - 1, true);
+ }
+
+ gc.setForeground(buttonBorderColor);
+ if (selection) {
+ gc.drawRoundRectangle(2, 2, buttonSize.x / 2, buttonSize.y, arc, arc);
+ } else {
+ gc.drawRoundRectangle(buttonSize.x / 2, 2, buttonSize.x / 2 + 2, buttonSize.y, arc, arc);
+ }
+
+ if (focusColor != null && mouseInside) {
+ gc.setForeground(focusColor);
+ gc.setLineWidth(2);
+ if (selection) {
+ gc.drawRoundRectangle(3, 3, buttonSize.x / 2, buttonSize.y - 1, 3, 3);
+ } else {
+ gc.drawRoundRectangle(buttonSize.x / 2 + 1, 3, buttonSize.x / 2, buttonSize.y - 2, 3, 3);
+ }
+ gc.setLineWidth(1);
+ }
+
+ }
+
+ /**
+ * Compute button size.
+ *
+ * @return the button size
+ */
+ private Point computeButtonSize() {
+ // Compute size for the left part
+ final Point sizeForLeftPart = gc.stringExtent(textForSelect);
+ // Compute size for the right part
+ final Point sizeForRightPart = gc.stringExtent(textForUnselect);
+
+ // Compute whole size
+ final int width = Math.max(sizeForLeftPart.x, sizeForRightPart.x) * 2 + 2 * insideMarginX;
+ final int height = Math.max(sizeForLeftPart.y, sizeForRightPart.y) + 2 * insideMarginY;
+
+ return new Point(width, height);
+ }
+
+ /**
+ * Draws the text besides the button.
+ *
+ * @param buttonSize whole size of the button
+ */
+ private void drawText(final Point buttonSize) {
+ gc.setForeground(getForeground());
+ gc.setBackground(getBackground());
+
+ final int widgetHeight = this.computeSize(0, 0, true).y;
+ final int textHeight = gc.stringExtent(text).y;
+ final int x = 2 + buttonSize.x + gap;
+
+ gc.drawString(text, x, (widgetHeight - textHeight) / 2);
+ }
+
+ /**
+ * Draw (eventually) the border around the button.
+ */
+ private void drawBorder() {
+ if (borderColor == null) {
+ return;
+ }
+
+ gc.setForeground(borderColor);
+ final Point temp = this.computeSize(0, 0, false);
+ if (round) {
+ gc.drawRoundRectangle(0, 0, temp.x - 2, temp.y - 2, 3, 3);
+ } else {
+ gc.drawRectangle(0, 0, temp.x - 2, temp.y - 2);
+ }
+
+ }
+
+ /**
+ * Fire the selection listeners.
+ *
+ * @param mouseEvent mouse event
+ * @return true if the selection could be changed, false otherwise
+ */
+ private boolean fireSelectionListeners(final MouseEvent mouseEvent) {
+ for (final SelectionListener listener : listOfSelectionListeners) {
+ final Event event = new Event();
+
+ event.button = mouseEvent.button;
+ event.display = getDisplay();
+ event.item = null;
+ event.widget = this;
+ event.data = null;
+ event.time = mouseEvent.time;
+ event.x = mouseEvent.x;
+ event.y = mouseEvent.y;
+
+ final SelectionEvent selEvent = new SelectionEvent(event);
+ listener.widgetSelected(selEvent);
+ if (!selEvent.doit) {
+ return false;
+ }
+ }
+ return 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();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ listOfSelectionListeners.add(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) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ listOfSelectionListeners.remove(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();
+ boolean disposeGC = false;
+ if (gc == null || gc.isDisposed()) {
+ gc = new GC(this);
+ disposeGC = true;
+ }
+
+ final Point buttonSize = computeButtonSize();
+ int width = buttonSize.x;
+ int height = buttonSize.y;
+
+ if (text != null && text.trim().length() > 0) {
+ final Point textSize = gc.textExtent(text);
+ width += textSize.x + gap + 1;
+ }
+
+ width += 4;
+ height += 6;
+
+ if (disposeGC) {
+ gc.dispose();
+ }
+
+ return new Point(width, height);
+ }
+
+ /**
+ * Gets the selection.
+ *
+ * @return the selection state of the button
+ */
+ public boolean getSelection() {
+ checkWidget();
+ return selection;
+ }
+
+ /**
+ * Sets the selection.
+ *
+ * @param selection the selection state of the button
+ */
+ public void setSelection(final boolean selection) {
+ checkWidget();
+ this.selection = selection;
+ }
+
+ /**
+ * Gets the text displayed for the selected value (default = "On").
+ *
+ * @return the text used to display the selection
+ */
+ public String getTextForSelect() {
+ checkWidget();
+ return textForSelect;
+ }
+
+ /**
+ * Sets the text displayed for the selected value (default = "On").
+ *
+ * @param textForSelect the text used to display the selection
+ */
+ public void setTextForSelect(final String textForSelect) {
+ checkWidget();
+ this.textForSelect = textForSelect;
+ }
+
+ /**
+ * Gets the text displayed for the unselected value (default = "Off").
+ *
+ * @return the text used to display the unselected option
+ */
+ public String getTextForUnselect() {
+ checkWidget();
+ return textForUnselect;
+ }
+
+ /**
+ * Sets the text displayed for the unselected value (default = "Off").
+ *
+ * @param textForUnselect the text used to display the unselected option
+ */
+ public void setTextForUnselect(final String textForUnselect) {
+ checkWidget();
+ this.textForUnselect = textForUnselect;
+ }
+
+ /**
+ * Gets the text corresponding to the button (default is "").
+ *
+ * @return the text displayed in the widget
+ */
+ public String getText() {
+ checkWidget();
+ return text;
+ }
+
+ /**
+ * Sets the text corresponding to the button (default is "").
+ *
+ * @param text the new text corresponding to the button (default is "")
+ */
+ public void setText(final String text) {
+ checkWidget();
+ this.text = text;
+ }
+
+ /**
+ * Checks if is if true, display round rectangles instead of rectangles
+ * (default value is true).
+ *
+ * @return the round flag
+ */
+ public boolean isRound() {
+ checkWidget();
+ return round;
+ }
+
+ /**
+ * Sets the if true, display round rectangles instead of rectangles (default
+ * value is true).
+ *
+ * @param round the round flag to set. If true, the widget is composed of
+ * round rectangle instead of rectangles
+ */
+ public void setRound(final boolean round) {
+ checkWidget();
+ this.round = round;
+ }
+
+ /**
+ * Gets the if not null, displays a rectangle (or a round rectangle) around
+ * the whole widget.
+ *
+ * @return the border's color. If null, no border is displayed
+ */
+ public Color getBorderColor() {
+ checkWidget();
+ return borderColor;
+ }
+
+ /**
+ * Sets the if not null, displays a rectangle (or a round rectangle) around
+ * the whole widget.
+ *
+ * @param borderColor the border's color. If null, no border is displayed.
+ */
+ public void setBorderColor(final Color borderColor) {
+ checkWidget();
+ this.borderColor = borderColor;
+ }
+
+ /**
+ * Gets the if not null, displays a glow effect when the mouse is over the
+ * widget.
+ *
+ * @return the focus color. If null, no focus effect is displayed.
+ */
+ public Color getFocusColor() {
+ checkWidget();
+ return focusColor;
+ }
+
+ /**
+ * Sets the if not null, displays a glow effect when the mouse is over the
+ * widget.
+ *
+ * @param focusColor the focus color to set. If null, no focus effect is
+ * displayed.
+ */
+ public void setFocusColor(final Color focusColor) {
+ checkWidget();
+ this.focusColor = focusColor;
+ }
+
+ /**
+ * Gets the colors when the button is selected.
+ *
+ * @return the foreground color of the left part of the widget (selection is
+ * on)
+ */
+ public Color getSelectedForegroundColor() {
+ checkWidget();
+ return selectedForegroundColor;
+ }
+
+ /**
+ * Sets the colors when the button is selected.
+ *
+ * @param selectedForegroundColor the new colors when the button is selected
+ */
+ public void setSelectedForegroundColor(final Color selectedForegroundColor) {
+ checkWidget();
+ this.selectedForegroundColor = selectedForegroundColor;
+ }
+
+ /**
+ * Gets the colors when the button is selected.
+ *
+ * @return the background color of the left part of the widget (selection is
+ * on)
+ */
+ public Color getSelectedBackgroundColor() {
+ checkWidget();
+ return selectedBackgroundColor;
+ }
+
+ /**
+ * Sets the colors when the button is selected.
+ *
+ * @param selectedBackgroundColor the new colors when the button is selected
+ */
+ public void setSelectedBackgroundColor(final Color selectedBackgroundColor) {
+ checkWidget();
+ this.selectedBackgroundColor = selectedBackgroundColor;
+ }
+
+ /**
+ * Gets the colors when the button is not selected.
+ *
+ * @return the foreground color of the left part of the widget (selection is
+ * on)
+ */
+ public Color getUnselectedForegroundColor() {
+ checkWidget();
+ return unselectedForegroundColor;
+ }
+
+ /**
+ * Sets the colors when the button is not selected.
+ *
+ * @param unselectedForegroundColor the foreground color of the left part of
+ * the widget (selection is on)
+ */
+ public void setUnselectedForegroundColor(final Color unselectedForegroundColor) {
+ checkWidget();
+ this.unselectedForegroundColor = unselectedForegroundColor;
+ }
+
+ /**
+ * Gets the colors when the button is not selected.
+ *
+ * @return the background color of the left part of the widget (selection is
+ * on)
+ */
+ public Color getUnselectedBackgroundColor() {
+ checkWidget();
+ return unselectedBackgroundColor;
+ }
+
+ /**
+ * Sets the colors when the button is not selected.
+ *
+ * @param unselectedBackgroundColor the background color of the left part of
+ * the widget (selection is on)
+ */
+ public void setUnselectedBackgroundColor(final Color unselectedBackgroundColor) {
+ checkWidget();
+ this.unselectedBackgroundColor = unselectedBackgroundColor;
+ }
+
+ /**
+ * Gets the colors for the button.
+ *
+ * @return the border color of the switch button
+ */
+ public Color getButtonBorderColor() {
+ checkWidget();
+ return buttonBorderColor;
+ }
+
+ /**
+ * Sets the colors for the button.
+ *
+ * @param buttonBorderColor the border color of the switch button
+ */
+ public void setButtonBorderColor(final Color buttonBorderColor) {
+ checkWidget();
+ this.buttonBorderColor = buttonBorderColor;
+ }
+
+ /**
+ * Gets the colors for the button.
+ *
+ * @return the first color of the toggle button
+ */
+ public Color getButtonBackgroundColor1() {
+ checkWidget();
+ return buttonBackgroundColor1;
+ }
+
+ /**
+ * Sets the colors for the button.
+ *
+ * @param buttonBackgroundColor1 the first color of the toggle button
+ */
+ public void setButtonBackgroundColor1(final Color buttonBackgroundColor1) {
+ checkWidget();
+ this.buttonBackgroundColor1 = buttonBackgroundColor1;
+ }
+
+ /**
+ * Gets the colors for the button.
+ *
+ * @return the second color of the toggle button
+ */
+ public Color getButtonBackgroundColor2() {
+ checkWidget();
+ return buttonBackgroundColor2;
+ }
+
+ /**
+ * Sets the colors for the button.
+ *
+ * @param buttonBackgroundColor2 the second color of the toggle button
+ */
+ public void setButtonBackgroundColor2(final Color buttonBackgroundColor2) {
+ checkWidget();
+ this.buttonBackgroundColor2 = buttonBackgroundColor2;
+ }
+
+ /**
+ * Gets the gap between the button and the text (default value is 5).
+ *
+ * @return the gap value
+ */
+ public int getGap() {
+ checkWidget();
+ return gap;
+ }
+
+ /**
+ * Sets the gap between the button and the text (default value is 5).
+ *
+ * @param gap the gap value to set
+ */
+ public void setGap(final int gap) {
+ checkWidget();
+ this.gap = gap;
+ }
+
+ /**
+ * Gets the inside margin.
+ *
+ * @return the margin 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 Point getInsideMargin() {
+ checkWidget();
+ return new Point(insideMarginX, insideMarginY);
+ }
+
+ /**
+ * Sets the inside margin.
+ *
+ * @param insideMarginX the new margin value (horizontal)
+ * @param insideMarginY the new margin value (vertical)
+ * @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 setInsideMargin(final int insideMarginX, final int insideMarginY) {
+ checkWidget();
+ this.insideMarginX = insideMarginX;
+ this.insideMarginY = insideMarginY;
+ }
+
+ /**
+ * Sets the inside margin.
+ *
+ * @param insideMargin the new margin 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 setInsideMargin(final Point insideMargin) {
+ checkWidget();
+ insideMarginX = insideMargin.x;
+ insideMarginY = insideMargin.y;
+ }
+
+ /**
+ * Gets the arc of rounded rectangles (default is 3).
+ *
+ * @return the arc value
+ */
+ public int getArc() {
+ checkWidget();
+ return arc;
+ }
+
+ /**
+ * Sets the arc of rounded rectangles (default is 3).
+ *
+ * @param arc the arc value to set
+ */
+ public void setArc(final int arc) {
+ checkWidget();
+ this.arc = arc;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/CPUUsageSample.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/CPUUsageSample.java
new file mode 100644
index 0000000..12c3b28
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/CPUUsageSample.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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.systemMonitor;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+/**
+ * Instances of this class represent a sample that contains the CPU usage.
+ */
+public class CPUUsageSample implements Sample {
+
+ /** The Constant PROCESS_CPU_TIME. */
+ private static final String PROCESS_CPU_TIME = "ProcessCpuTime";
+
+ /** The Constant OBJECT_NAME_ATTRIBUTE. */
+ private static final String OBJECT_NAME_ATTRIBUTE = "java.lang:type=OperatingSystem";
+
+ /** The m bean server connection. */
+ private final MBeanServerConnection mBeanServerConnection = ManagementFactory.getPlatformMBeanServer();
+
+ /** The object name. */
+ private ObjectName objectName;
+
+ /** The time. */
+ private long time;
+
+ /** The process time. */
+ private long processTime;
+
+ /**
+ * Constructor.
+ */
+ public CPUUsageSample() {
+ try {
+ this.objectName = new ObjectName(OBJECT_NAME_ATTRIBUTE);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value
+ * @see org.mihalis.opal.systemMonitor.Sample#getValue()
+ */
+ @Override
+ public double getValue() {
+ try {
+ float f = ((Long) this.mBeanServerConnection.getAttribute(this.objectName, PROCESS_CPU_TIME)).longValue() - this.processTime;
+ f /= System.nanoTime() - this.time;
+ this.time = System.nanoTime();
+ this.processTime = ((Long) this.mBeanServerConnection.getAttribute(this.objectName, PROCESS_CPU_TIME)).longValue();
+ return f;
+ } catch (final Exception localException) {
+ throw new RuntimeException(localException);
+ }
+ }
+
+ /**
+ * Gets the max value.
+ *
+ * @return the max value
+ * @see org.mihalis.opal.systemMonitor.Sample#getMaxValue()
+ */
+ @Override
+ public double getMaxValue() {
+ return 1.0d;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/HeapMemorySample.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/HeapMemorySample.java
new file mode 100644
index 0000000..48ffbcf
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/HeapMemorySample.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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.systemMonitor;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeDataSupport;
+
+/**
+ * Instances of this class represent a sample that contains the Thread Usage of
+ * the running application.
+ */
+public class HeapMemorySample implements Sample {
+
+ /** The Constant COMMITTED. */
+ private static final String COMMITTED = "committed";
+
+ /** The Constant USED. */
+ private static final String USED = "used";
+
+ /** The Constant HEAP_MEMORY_USAGE. */
+ private static final String HEAP_MEMORY_USAGE = "HeapMemoryUsage";
+
+ /** The Constant OBJECT_NAME_ATTRIBUTE. */
+ private static final String OBJECT_NAME_ATTRIBUTE = "java.lang:type=Memory";
+
+ /** The m bean server connection. */
+ private final MBeanServerConnection mBeanServerConnection = ManagementFactory.getPlatformMBeanServer();
+
+ /** The object name. */
+ private final ObjectName objectName;
+
+ /**
+ * Constructor.
+ */
+ HeapMemorySample() {
+ try {
+ this.objectName = new ObjectName(OBJECT_NAME_ATTRIBUTE);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value
+ * @see org.mihalis.opal.systemMonitor.Sample#getValue()
+ */
+ @Override
+ public double getValue() {
+ try {
+ return ((Long) ((CompositeDataSupport) this.mBeanServerConnection.getAttribute(this.objectName, HEAP_MEMORY_USAGE)).get(USED)).longValue() / 1024.0D / 1024.0D;
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ /**
+ * Gets the max value.
+ *
+ * @return the max value
+ * @see org.mihalis.opal.systemMonitor.Sample#getMaxValue()
+ */
+ @Override
+ public double getMaxValue() {
+ try {
+ return ((Long) ((CompositeDataSupport) this.mBeanServerConnection.getAttribute(this.objectName, HEAP_MEMORY_USAGE)).get(COMMITTED)).longValue() / 1024.0D / 1024.0D;
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/PhysicalMemorySample.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/PhysicalMemorySample.java
new file mode 100644
index 0000000..e0447c4
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/PhysicalMemorySample.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * 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.systemMonitor;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+/**
+ * Instances of this class represent a sample that contains the OS memory usage.
+ */
+public class PhysicalMemorySample implements Sample {
+
+ /** The Constant TOTAL_PHYSICAL_MEMORY_SIZE. */
+ private static final String TOTAL_PHYSICAL_MEMORY_SIZE = "TotalPhysicalMemorySize";
+
+ /** The Constant FREE_PHYSICAL_MEMORY_SIZE. */
+ private static final String FREE_PHYSICAL_MEMORY_SIZE = "FreePhysicalMemorySize";
+
+ /** The Constant OBJECT_NAME_ATTRIBUTE. */
+ private static final String OBJECT_NAME_ATTRIBUTE = "java.lang:type=OperatingSystem";
+
+ /** The m bean server connection. */
+ private final MBeanServerConnection mBeanServerConnection = ManagementFactory.getPlatformMBeanServer();
+
+ /** The object name. */
+ private ObjectName objectName;
+
+ /**
+ * Constructor.
+ */
+ PhysicalMemorySample() {
+ try {
+ this.objectName = new ObjectName(OBJECT_NAME_ATTRIBUTE);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value
+ * @see org.mihalis.opal.systemMonitor.Sample#getValue()
+ */
+ @Override
+ public double getValue() {
+ try {
+ final double memSize = ((Long) this.mBeanServerConnection.getAttribute(this.objectName, FREE_PHYSICAL_MEMORY_SIZE)).longValue() / 1024.0d / 1024.0d;
+ return getMaxValue() - memSize;
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets the max value.
+ *
+ * @return the max value
+ * @see org.mihalis.opal.systemMonitor.Sample#getMaxValue()
+ */
+ @Override
+ public double getMaxValue() {
+ try {
+ return ((Long) this.mBeanServerConnection.getAttribute(this.objectName, TOTAL_PHYSICAL_MEMORY_SIZE)).longValue() / 1024.0d / 1024.0d;
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/Sample.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/Sample.java
new file mode 100644
index 0000000..197bc4a
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/Sample.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2011 2Laurent 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.systemMonitor;
+
+/**
+ * This interface represents a data sample that will be displayed in the
+ * SystemMonitor widget.
+ */
+public interface Sample {
+
+ /**
+ * Gets the value.
+ *
+ * @return the current value of the sample
+ */
+ double getValue();
+
+ /**
+ * Gets the max value.
+ *
+ * @return the max value of the sample
+ */
+ double getMaxValue();
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleFactory.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleFactory.java
new file mode 100644
index 0000000..dfbd991
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleFactory.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * 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.systemMonitor;
+
+import org.eclipse.swt.graphics.RGB;
+import org.mihalis.opal.utils.ResourceManager;
+
+/**
+ * This class is a factory that returns the built-o, samples.
+ */
+public class SampleFactory {
+
+ /** SampleFactory instance. */
+ private static SampleFactory instance;
+
+ /**
+ * Constructor.
+ */
+ private SampleFactory() {
+ }
+
+ /**
+ * Gets the sampleFactory instance.
+ *
+ * @return the instance of the factory
+ */
+ public static SampleFactory getInstance() {
+ if (instance == null) {
+ instance = new SampleFactory();
+ }
+ return instance;
+ }
+
+ /**
+ * Give a built-in sample.
+ *
+ * @param identifier Identifier
+ * @return the sample that corresponds to the identifier
+ */
+ public SampleWrapper getSample(final SampleIdentifier identifier) {
+ switch (identifier) {
+ case CPU_USAGE: {
+ final SampleWrapper sr = new SampleWrapper(new CPUUsageSample());
+ sr.setColor(new RGB(128, 25, 0));
+ sr.setCaption(ResourceManager.CPU_USAGE + ":");
+ sr.setFormatPattern("%{percentValue}.0f%%");
+ return sr;
+ }
+ case HEAP_MEMORY: {
+ final SampleWrapper sr = new SampleWrapper(new HeapMemorySample());
+ sr.setColor(new RGB(111, 83, 0));
+ sr.setCaption(ResourceManager.HEAP_MEMORY + ":");
+ sr.setFormatPattern("%{value},.2fMB / %{maxValue},.2fMB");
+ return sr;
+ }
+ case PHYSICAL_MEMORY: {
+ final SampleWrapper sr = new SampleWrapper(new PhysicalMemorySample());
+ sr.setColor(new RGB(15, 75, 0));
+ sr.setCaption(ResourceManager.PHYSICAL_MEMORY + ":");
+ sr.setFormatPattern("%{value},.0fMB / %{maxValue},.0fMB");
+ return sr;
+ }
+ default: {
+ final SampleWrapper sr = new SampleWrapper(new ThreadsUsageSample());
+ sr.setColor(new RGB(0, 77, 88));
+ sr.setCaption(ResourceManager.THREADS + ":");
+ sr.setFormatPattern("%{value},.0f / %{maxValue},.0f (Peak)");
+ return sr;
+ }
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleIdentifier.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleIdentifier.java
new file mode 100644
index 0000000..1cdfe94
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleIdentifier.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * 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.systemMonitor;
+
+/**
+ * This enumeration lists all built-in samples.
+ */
+public enum SampleIdentifier {
+
+ /** The physical memory. */
+ PHYSICAL_MEMORY,
+ /** The heap memory. */
+ HEAP_MEMORY,
+ /** The threads. */
+ THREADS,
+ /** The cpu usage. */
+ CPU_USAGE
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleWrapper.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleWrapper.java
new file mode 100644
index 0000000..5fabf53
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SampleWrapper.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * 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.systemMonitor;
+
+import java.util.List;
+
+import org.eclipse.swt.graphics.RGB;
+import org.mihalis.opal.utils.FixedSizeQueue;
+
+/**
+ * Instances of this class are wrapper that contains a sample, its data, color,
+ * caption, formatPattern...
+ */
+public class SampleWrapper {
+
+ /** The color. */
+ private RGB color;
+
+ /** The border color. */
+ private RGB borderColor;
+
+ /** The caption. */
+ private String caption;
+
+ /** The format pattern. */
+ private String formatPattern;
+
+ /** The sample. */
+ private final Sample sample;
+
+ /** The data. */
+ private final FixedSizeQueue<Double> data;
+
+ /** The last value. */
+ private Double lastValue;
+
+ /** The last max value. */
+ private Double lastMaxValue;
+
+ /** The max value. */
+ private Double maxValue;
+
+ /**
+ * Constructor.
+ *
+ * @param sample associated sample
+ */
+ SampleWrapper(final Sample sample) {
+ super();
+ this.sample = sample;
+ this.color = new RGB(255, 255, 216);
+ this.caption = "";
+ this.formatPattern = "";
+ this.data = new FixedSizeQueue<Double>(1000);
+ this.lastValue = 0d;
+ this.lastMaxValue = 0d;
+ this.maxValue = 0d;
+ createBorderColor();
+ }
+
+ /**
+ * Create the border color.
+ */
+ private void createBorderColor() {
+ this.borderColor = new RGB(Math.min(this.color.red * 2, 255), Math.min(this.color.green * 2, 255), Math.min(this.color.blue * 2, 255));
+ }
+
+ /**
+ * Collect a sample.
+ */
+ void collect() {
+ this.lastValue = this.sample.getValue();
+ this.maxValue = Math.max(this.lastMaxValue, this.sample.getMaxValue());
+ this.lastMaxValue = this.sample.getMaxValue();
+ this.data.put(this.lastValue);
+ }
+
+ /**
+ * Gets the border color.
+ *
+ * @return the border color
+ */
+ public RGB getBorderColor() {
+ return this.borderColor;
+ }
+
+ /**
+ * Gets the caption.
+ *
+ * @return the caption
+ */
+ public String getCaption() {
+ return this.caption;
+ }
+
+ /**
+ * Gets the color.
+ *
+ * @return the color
+ */
+ RGB getColor() {
+ return this.color;
+ }
+
+ /**
+ * Gets the data.
+ *
+ * @return all data
+ */
+ public List<Double> getData() {
+ return this.data.getValues();
+ }
+
+ /**
+ * Gets the format pattern.
+ *
+ * @return the format pattern
+ */
+ String getFormatPattern() {
+ return this.formatPattern;
+ }
+
+ /**
+ * Gets the last max value.
+ *
+ * @return the last max value collected
+ */
+ public Double getLastMaxValue() {
+ return this.lastMaxValue;
+ }
+
+ /**
+ * Gets the last value.
+ *
+ * @return the last collected value
+ */
+ public Double getLastValue() {
+ return this.lastValue;
+ }
+
+ /**
+ * Gets the max value.
+ *
+ * @return the max value
+ */
+ public double getMaxValue() {
+ return this.maxValue;
+ }
+
+ /**
+ * Gets the number of collected elements.
+ *
+ * @return the number of collected elements
+ */
+ public int getNumberOfCollectedElements() {
+ return this.data.getSize();
+ }
+
+ /**
+ * Gets the sample.
+ *
+ * @return the sample
+ */
+ Sample getSample() {
+ return this.sample;
+ }
+
+ /**
+ * Resize.
+ *
+ * @param newSize new size of the data collector array
+ */
+ public void resize(final int newSize) {
+ this.data.resizeTo(newSize);
+ }
+
+ /**
+ * Sets the caption.
+ *
+ * @param caption the caption to set
+ * @return the sample wrapper
+ */
+ SampleWrapper setCaption(final String caption) {
+ this.caption = caption;
+ return this;
+ }
+
+ /**
+ * Sets the color.
+ *
+ * @param color the color to set
+ * @return the sample wrapper
+ */
+ SampleWrapper setColor(final RGB color) {
+ this.color = color;
+ createBorderColor();
+ return this;
+ }
+
+ /**
+ * Sets the format pattern.
+ *
+ * @param formatPattern the format pattern to set
+ * @return the sample wrapper
+ */
+ SampleWrapper setFormatPattern(final String formatPattern) {
+ this.formatPattern = formatPattern;
+ return this;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SystemMonitor.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SystemMonitor.java
new file mode 100644
index 0000000..905de8d
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/SystemMonitor.java
@@ -0,0 +1,518 @@
+/*******************************************************************************
+ * 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.systemMonitor;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+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.FontData;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.Region;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Instances of this class are system monitors.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ */
+public class SystemMonitor extends Canvas {
+
+ /** The samples. */
+ private final Map<String, SampleWrapper> samples;
+
+ /** The caption visible. */
+ private boolean captionVisible;
+
+ /** The gc. */
+ private GC gc;
+
+ /** The border color. */
+ private final Color borderColor;
+
+ /** The grid color background. */
+ private final Color gridColorBackground;
+
+ /** The grid color. */
+ private final Color gridColor;
+
+ /** The grid size. */
+ private final int gridSize;
+
+ /** The refresh time. */
+ private final int refreshTime;
+
+ /** The keep running. */
+ private boolean keepRunning;
+
+ /**
+ * 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>'in 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 super
+ * classes.
+ * </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 SystemMonitor(final Composite parent, final int style) {
+ super(parent, style | SWT.DOUBLE_BUFFERED);
+ this.samples = new LinkedHashMap<String, SampleWrapper>();
+ this.captionVisible = true;
+ this.borderColor = new Color(getDisplay(), 96, 96, 96);
+ this.gridColor = new Color(getDisplay(), 89, 89, 89);
+ this.gridColorBackground = new Color(getDisplay(), 50, 50, 50);
+ this.gridSize = 12;
+ this.refreshTime = 300;
+ this.keepRunning = true;
+
+ createListeners();
+ launchDataCollecting();
+ }
+
+ /**
+ * Constructs a new instance of this class given its parent, a style value
+ * describing its behavior and appearance. Also for a given grid size and
+ * refresh interval
+ * <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>'in 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 super
+ * classes.
+ * </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 gridSize the grid size
+ * @param refeshTime the refesh time
+ * @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 SystemMonitor(final Composite parent, final int style, final int gridSize, final int refeshTime) {
+ super(parent, style | SWT.DOUBLE_BUFFERED);
+ this.samples = new LinkedHashMap<String, SampleWrapper>();
+ this.captionVisible = true;
+ this.borderColor = new Color(getDisplay(), 96, 96, 96);
+ this.gridColor = new Color(getDisplay(), 89, 89, 89);
+ this.gridColorBackground = new Color(getDisplay(), 50, 50, 50);
+ this.gridSize = gridSize;
+ this.refreshTime = refeshTime;
+ this.keepRunning = true;
+
+ createListeners();
+ launchDataCollecting();
+ }
+
+ /**
+ * Create the listeners.
+ */
+ private void createListeners() {
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(final PaintEvent e) {
+ SystemMonitor.this.paintControl(e);
+ }
+ });
+ addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ SystemMonitor.this.borderColor.dispose();
+ SystemMonitor.this.gridColor.dispose();
+ SystemMonitor.this.gridColorBackground.dispose();
+ }
+ });
+ addControlListener(new ControlAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse.swt.events.ControlEvent)
+ */
+ @Override
+ public void controlResized(final ControlEvent e) {
+ for (final SampleWrapper sample : SystemMonitor.this.samples.values()) {
+ sample.resize(getClientArea().width / SystemMonitor.this.gridSize - 1);
+ }
+ }
+ });
+ }
+
+ /**
+ * Draws the widget.
+ *
+ * @param e paint event
+ */
+ private void paintControl(final PaintEvent e) {
+ this.gc = e.gc;
+ e.gc.setAdvanced(true);
+ e.gc.setAntialias(SWT.ON);
+ drawBackground();
+ drawGrid();
+
+ for (final SampleWrapper sample : this.samples.values()) {
+ drawData(sample);
+ }
+
+ if (this.captionVisible && this.samples.size() == 1) {
+ drawCaption();
+ }
+
+ }
+
+ /**
+ * Draws the background.
+ */
+ private void drawBackground() {
+ final Rectangle clientArea = getClientArea();
+ this.gc.setForeground(this.borderColor);
+ this.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ this.gc.fillRoundRectangle(clientArea.x, clientArea.y, clientArea.width, clientArea.height, 5, 5);
+ this.gc.drawRoundRectangle(clientArea.x, clientArea.y, clientArea.width, clientArea.height, 5, 5);
+ }
+
+ /**
+ * Draw the grid.
+ */
+ private void drawGrid() {
+ final Rectangle clientArea = getClientArea();
+ this.gc.setClipping(clientArea.x + 3, clientArea.y + 3, clientArea.width - 6, clientArea.height - 6);
+ this.gc.setForeground(this.gridColor);
+ this.gc.setBackground(this.gridColorBackground);
+ this.gc.fillRectangle(getClientArea());
+ for (int x = this.gridSize / 2; x < clientArea.x + clientArea.width; x += this.gridSize) {
+ this.gc.drawLine(x, clientArea.x, x, clientArea.height);
+ }
+ for (int y = this.gridSize / 2; y < clientArea.y + clientArea.height; y += this.gridSize) {
+ this.gc.drawLine(clientArea.x, y, clientArea.width, y);
+ }
+
+ this.gc.setAlpha(180);
+ this.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ this.gc.fillRoundRectangle(clientArea.x + 10, clientArea.y + 10, clientArea.width + 20, clientArea.width + 20, 5, 5);
+ this.gc.setAlpha(255);
+
+ this.gc.setClipping(clientArea);
+ }
+
+ /**
+ * Draw the data.
+ *
+ * @param sample sample that contains data
+ */
+ private void drawData(final SampleWrapper sample) {
+ final List<Double> data = sample.getData();
+
+ if (data == null || data.size() < 2) {
+ return;
+ }
+
+ final Rectangle clientArea = getClientArea();
+ final double maxValue = sample.getMaxValue();
+ this.gc.setClipping(clientArea);
+ final Color borderColor = new Color(getDisplay(), sample.getBorderColor());
+ final Color color = new Color(getDisplay(), sample.getColor());
+ final int[] pointArray = new int[2 * (data.size() + 2)];
+
+ final int availableWidth = clientArea.width - this.gridSize;
+ final int availableHeight = (int) ((clientArea.height - this.gridSize) * 0.98f);
+
+ int x = this.gridSize / 2 + availableWidth - (data.size() - 1) * this.gridSize;
+
+ // First point
+ pointArray[0] = x;
+ pointArray[1] = clientArea.y + clientArea.height + this.gridSize / 2 - (this.captionVisible ? 25 : 0);
+
+ // Following points
+ int index = 2;
+ double maxDisplayedValue = -1d;
+ for (final Double datum : data) {
+ pointArray[index++] = x;
+ pointArray[index++] = clientArea.height - (int) (this.gridSize / 2 + availableHeight * datum / maxValue);
+ x += this.gridSize;
+ maxDisplayedValue = Math.max(maxDisplayedValue, datum);
+ }
+
+ // Last point
+ pointArray[index++] = x - this.gridSize;
+ pointArray[index++] = clientArea.y + clientArea.height + this.gridSize / 2 - (this.captionVisible ? 25 : 0);
+
+ // Draw a gradient rectangle
+ this.gc.setAlpha(this.samples.size() == 1 ? 210 : 150);
+ final Region region = new Region(getDisplay());
+ region.add(pointArray);
+ this.gc.setClipping(region);
+ this.gc.setForeground(borderColor);
+ this.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ this.gc.fillGradientRectangle(this.gridSize / 2, clientArea.height - (int) (this.gridSize / 2 + availableHeight * maxDisplayedValue / maxValue), availableWidth, (int) (availableHeight * maxDisplayedValue / maxValue), true);
+
+ // Draw the polyline
+ this.gc.setClipping(clientArea);
+ this.gc.setForeground(borderColor);
+ this.gc.drawPolygon(pointArray);
+
+ region.dispose();
+ borderColor.dispose();
+ color.dispose();
+ this.gc.setAlpha(255);
+
+ }
+
+ /**
+ * Draw caption.
+ */
+ private void drawCaption() {
+ for (final SampleWrapper sample : this.samples.values()) {
+ if (sample.getCaption() != null && !sample.getCaption().equals("")) {
+ drawCaptionForSample(sample);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Draws a caption for a given sample.
+ *
+ * @param sample sample
+ */
+ private void drawCaptionForSample(final SampleWrapper sample) {
+ final Rectangle clientArea = getClientArea();
+ this.gc.setClipping(clientArea);
+ this.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ this.gc.fillRectangle(clientArea.x, clientArea.y + clientArea.height - 19, clientArea.width, 19);
+
+ final Color color = new Color(getDisplay(), sample.getBorderColor());
+ this.gc.setForeground(color);
+ final FontData[] fontData = getFont().getFontData();
+ for (final FontData f : fontData) {
+ f.setHeight(9);
+ }
+ final Font font = new Font(getDisplay(), fontData);
+ this.gc.setFont(getFont());
+
+ final String format = sample.getFormatPattern().replace("{value}", "1$").replace("{maxValue}", "2$").replace("{percentValue}", "3$");
+ final String formattedCaption = String.format(format, //
+ new Object[] { sample.getLastValue(), //
+ sample.getLastMaxValue(), //
+ Double.valueOf(sample.getLastValue() / sample.getLastMaxValue() * 100.0D) });
+
+ this.gc.drawString(sample.getCaption() + " : " + formattedCaption, clientArea.x + this.gridSize, clientArea.y + clientArea.height - 19);
+
+ font.dispose();
+ color.dispose();
+
+ }
+
+ /**
+ * Launch the data collecting process.
+ */
+ private void launchDataCollecting() {
+ getDisplay().timerExec(this.refreshTime, new Runnable() {
+
+ @Override
+ public void run() {
+ collect();
+ if (!SystemMonitor.this.isDisposed() && SystemMonitor.this.keepRunning && !getDisplay().isDisposed()) {
+ getDisplay().timerExec(SystemMonitor.this.refreshTime, this);
+ }
+ }
+ });
+ }
+
+ /**
+ * Collect data.
+ */
+ private void collect() {
+ for (final SampleWrapper sample : this.samples.values()) {
+ sample.collect();
+ }
+ if (!this.isDisposed() && !getDisplay().isDisposed()) {
+ getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ if (!SystemMonitor.this.isDisposed()) {
+ redraw();
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * 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>'in 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 super
+ * classes.
+ * </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 identifier the identifier
+ * @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 SystemMonitor(final Composite parent, final int style, final SampleIdentifier identifier) {
+ this(parent, style);
+ final SampleWrapper wrapper = SampleFactory.getInstance().getSample(identifier);
+ addSample(identifier.name(), wrapper);
+ this.captionVisible = !wrapper.getCaption().trim().equals("");
+ }
+
+ /**
+ * Add a sample.
+ *
+ * @param id identifier
+ * @param sample sample to add
+ */
+ public void addSample(final String id, final Sample sample) {
+ this.samples.put(id, new SampleWrapper(sample));
+ }
+
+ /**
+ * Add a sample.
+ *
+ * @param id identifier
+ * @param sampleWrapper sample wrapper
+ */
+ private void addSample(final String id, final SampleWrapper sampleWrapper) {
+ this.samples.put(id, sampleWrapper);
+ }
+
+ /**
+ * Displays all built-in samples.
+ */
+ public void displayAll() {
+ this.samples.clear();
+ addSample(SampleIdentifier.CPU_USAGE.name(), SampleFactory.getInstance().getSample(SampleIdentifier.CPU_USAGE));
+ addSample(SampleIdentifier.HEAP_MEMORY.name(), SampleFactory.getInstance().getSample(SampleIdentifier.HEAP_MEMORY));
+ addSample(SampleIdentifier.PHYSICAL_MEMORY.name(), SampleFactory.getInstance().getSample(SampleIdentifier.PHYSICAL_MEMORY));
+ addSample(SampleIdentifier.THREADS.name(), SampleFactory.getInstance().getSample(SampleIdentifier.THREADS));
+ }
+
+ /**
+ * Checks if is caption visible.
+ *
+ * @return <code>true</code> if the caption is visible, <code>false</code>
+ * otherwise
+ */
+ public boolean isCaptionVisible() {
+ return this.captionVisible;
+ }
+
+ /**
+ * Set the caption for a given sample.
+ *
+ * @param id sample identifier
+ * @param caption caption to set
+ */
+ public void setCaption(final String id, final String caption) {
+ if (!this.samples.containsKey(id)) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.samples.get(id).setCaption(caption);
+ }
+
+ /**
+ * Sets the caption visible.
+ *
+ * @param captionVisible if true, the caption is visible
+ */
+ public void setCaptionVisible(final boolean captionVisible) {
+ this.captionVisible = captionVisible;
+ }
+
+ /**
+ * Set the color for a given sample.
+ *
+ * @param id sample identifier
+ * @param color color to set
+ */
+ public void setColor(final String id, final RGB color) {
+ if (!this.samples.containsKey(id)) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.samples.get(id).setColor(color);
+ }
+
+ /**
+ * Set the pattern for a given sample.
+ *
+ * @param id sample identifier
+ * @param pattern pattern to set
+ */
+ public void setFormatPattern(final String id, final String pattern) {
+ if (!this.samples.containsKey(id)) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ this.samples.get(id).setFormatPattern(pattern);
+ }
+
+ /**
+ * Stop the data collecting process.
+ */
+ public void stop() {
+ this.keepRunning = false;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/ThreadsUsageSample.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/ThreadsUsageSample.java
new file mode 100644
index 0000000..f96a065
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/systemMonitor/ThreadsUsageSample.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * 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.systemMonitor;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+/**
+ * Instances of this class represent a sample that contains the Thread Usage of
+ * the running application.
+ */
+public class ThreadsUsageSample implements Sample {
+
+ /** The Constant PEAK_THREAD_COUNT. */
+ private static final String PEAK_THREAD_COUNT = "PeakThreadCount";
+
+ /** The Constant THREAD_COUNT. */
+ private static final String THREAD_COUNT = "ThreadCount";
+
+ /** The Constant OBJECT_NAME_ATTRIBUTE. */
+ private static final String OBJECT_NAME_ATTRIBUTE = "java.lang:type=Threading";
+
+ /** The m bean server connection. */
+ private final MBeanServerConnection mBeanServerConnection = ManagementFactory.getPlatformMBeanServer();
+
+ /** The object name. */
+ private ObjectName objectName;
+
+ /**
+ * Constructor.
+ */
+ ThreadsUsageSample() {
+ try {
+ this.objectName = new ObjectName(OBJECT_NAME_ATTRIBUTE);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value
+ * @see org.mihalis.opal.systemMonitor.Sample#getValue()
+ */
+ @Override
+ public double getValue() {
+ try {
+ return ((Integer) this.mBeanServerConnection.getAttribute(this.objectName, THREAD_COUNT)).intValue();
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets the max value.
+ *
+ * @return the max value
+ * @see org.mihalis.opal.systemMonitor.Sample#getMaxValue()
+ */
+ @Override
+ public double getMaxValue() {
+ try {
+ return ((Integer) this.mBeanServerConnection.getAttribute(this.objectName, PEAK_THREAD_COUNT)).intValue();
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/textAssist/TextAssist.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/textAssist/TextAssist.java
new file mode 100644
index 0000000..21d8cf9
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/textAssist/TextAssist.java
@@ -0,0 +1,985 @@
+/*******************************************************************************
+ * 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:
+ * IBM Corporation - initial API and implementation (Snippet 320)
+ * Laurent CARON (laurent.caron@gmail.com) - Make a widget from the snippet
+ *******************************************************************************/
+package org.mihalis.opal.textAssist;
+
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.VerifyListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * Instances of this class are selectable user interface objects that allow the
+ * user to enter and modify text. The difference with the Text widget is that
+ * when the user types something, some propositions are displayed.
+ *
+ * @see org.eclipse.swt.widgets.Text
+ */
+public class TextAssist extends Composite {
+
+ /** The Constant SETTEXT_KEY. */
+ private static final String SETTEXT_KEY = "org.mihalis.opal.textAssist.TextAssist.settext";
+
+ /** The text. */
+ private final Text text;
+
+ /** The popup. */
+ private final Shell popup;
+
+ /** The table. */
+ private final Table table;
+
+ /** The content provider. */
+ private TextAssistContentProvider contentProvider;
+
+ /** The number of lines. */
+ private int numberOfLines;
+
+ /**
+ * 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 contentProvider the content provider
+ * @see SWT#SINGLE
+ * @see SWT#MULTI
+ * @see SWT#READ_ONLY
+ * @see SWT#WRAP
+ * @see SWT#LEFT
+ * @see SWT#RIGHT
+ * @see SWT#CENTER
+ * @see SWT#PASSWORD
+ * @see SWT#SEARCH
+ * @see SWT#ICON_SEARCH
+ * @see SWT#ICON_CANCEL
+ * @see Widget#checkSubclass
+ * @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 TextAssist(final Composite parent, final int style, final TextAssistContentProvider contentProvider) {
+ super(parent, SWT.NONE);
+ this.contentProvider = contentProvider;
+ this.contentProvider.setTextAssist(this);
+
+ setLayout(new FillLayout());
+ numberOfLines = 10;
+ text = new Text(this, style);
+ popup = new Shell(getDisplay(), SWT.ON_TOP);
+ popup.setLayout(new FillLayout());
+ table = new Table(popup, SWT.SINGLE);
+
+ addTextListener();
+ addTableLittle();
+
+ final int[] events = new int[] { SWT.Move, SWT.FocusOut };
+ for (final int event : events) {
+ getShell().addListener(event, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ popup.setVisible(false);
+ }
+ });
+ }
+
+ }
+
+ /**
+ * Adds the text listener.
+ */
+ private void addTextListener() {
+ text.addListener(SWT.KeyDown, createKeyDownListener());
+ text.addListener(SWT.Modify, createModifyListener());
+ text.addListener(SWT.FocusOut, createFocusOutListener());
+ }
+
+ /**
+ * Adds the table little.
+ */
+ private void addTableLittle() {
+ table.addListener(SWT.DefaultSelection, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ text.setText(table.getSelection()[0].getText());
+ popup.setVisible(false);
+ }
+ });
+ table.addListener(SWT.KeyDown, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ if (event.keyCode == SWT.ESC) {
+ popup.setVisible(false);
+ }
+ }
+ });
+
+ table.addListener(SWT.FocusOut, createFocusOutListener());
+ }
+
+ /**
+ * Creates the key down listener.
+ *
+ * @return a listener for the keydown event
+ */
+ private Listener createKeyDownListener() {
+ return new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ switch (event.keyCode) {
+ case SWT.ARROW_DOWN:
+ int index = (table.getSelectionIndex() + 1) % table.getItemCount();
+ table.setSelection(index);
+ event.doit = false;
+ break;
+ case SWT.ARROW_UP:
+ index = table.getSelectionIndex() - 1;
+ if (index < 0) {
+ index = table.getItemCount() - 1;
+ }
+ table.setSelection(index);
+ event.doit = false;
+ break;
+ case SWT.CR:
+ case SWT.KEYPAD_CR:
+ if (popup.isVisible() && table.getSelectionIndex() != -1) {
+ text.setText(table.getSelection()[0].getText());
+ popup.setVisible(false);
+ }
+ break;
+ case SWT.ESC:
+ popup.setVisible(false);
+ break;
+ }
+ }
+ };
+ }
+
+ /**
+ * Creates the modify listener.
+ *
+ * @return a listener for the modify event
+ */
+ private Listener createModifyListener() {
+ return new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ if (text.getData(SETTEXT_KEY) != null && Boolean.TRUE.equals(text.getData(SETTEXT_KEY))) {
+ text.setData(SETTEXT_KEY, null);
+ return;
+ }
+ text.setData(SETTEXT_KEY, null);
+
+ final String string = text.getText();
+ if (string.length() == 0) {
+ popup.setVisible(false);
+ return;
+ }
+
+ List<String> values = contentProvider.getContent(string);
+ if (values == null || values.isEmpty()) {
+ popup.setVisible(false);
+ return;
+ }
+
+ if (values.size() > numberOfLines) {
+ values = values.subList(0, numberOfLines);
+ }
+
+ table.removeAll();
+ final int numberOfRows = Math.min(values.size(), numberOfLines);
+ for (int i = 0; i < numberOfRows; i++) {
+ final TableItem tableItem = new TableItem(table, SWT.NONE);
+ tableItem.setText(values.get(i));
+ }
+
+ final Point point = text.toDisplay(text.getLocation().x, text.getSize().y + text.getBorderWidth() - 3);
+ int x = point.x;
+ int y = point.y;
+
+ final Rectangle displayRect = getMonitor().getClientArea();
+ final Rectangle parentRect = getDisplay().map(getParent(), null, getBounds());
+ popup.pack();
+ final int width = popup.getBounds().width;
+ final int height = popup.getBounds().height;
+
+ if (y + height > displayRect.y + displayRect.height) {
+ y = parentRect.y - height;
+ }
+ if (x + width > displayRect.x + displayRect.width) {
+ x = displayRect.x + displayRect.width - width;
+ }
+
+ popup.setLocation(x, y);
+ popup.setVisible(true);
+
+ }
+ };
+ }
+
+ /**
+ * Creates the focus out listener.
+ *
+ * @return a listener for the FocusOut event
+ */
+ private Listener createFocusOutListener() {
+ return new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ /*
+ * Async is needed to wait until focus reaches its new Control
+ */
+ TextAssist.this.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (TextAssist.this.isDisposed() || TextAssist.this.getDisplay().isDisposed()) {
+ return;
+ }
+ final Control control = TextAssist.this.getDisplay().getFocusControl();
+ if (control == null || control != text && control != table) {
+ popup.setVisible(false);
+ }
+ }
+ });
+ }
+ };
+ }
+
+ /**
+ * Gets the background.
+ *
+ * @return the background
+ * @see org.eclipse.swt.widgets.Control#getBackground()
+ */
+ @Override
+ public Color getBackground() {
+ checkWidget();
+ return text.getBackground();
+ }
+
+ /**
+ * Gets the content provider.
+ *
+ * @return the contentProvider
+ */
+ public TextAssistContentProvider getContentProvider() {
+ checkWidget();
+ return contentProvider;
+ }
+
+ /**
+ * Gets the foreground.
+ *
+ * @return the foreground
+ * @see org.eclipse.swt.widgets.Control#getForeground()
+ */
+ @Override
+ public Color getForeground() {
+ checkWidget();
+ return super.getForeground();
+ }
+
+ /**
+ * Sets the background.
+ *
+ * @param color the new background
+ * @see org.eclipse.swt.widgets.Text#setBackground(org.eclipse.swt.graphics.Color)
+ */
+ @Override
+ public void setBackground(final Color color) {
+ checkWidget();
+ text.setBackground(color);
+ }
+
+ /**
+ * Sets the content provider.
+ *
+ * @param contentProvider the contentProvider to set
+ */
+ public void setContentProvider(final TextAssistContentProvider contentProvider) {
+ checkWidget();
+ this.contentProvider = contentProvider;
+ }
+
+ /**
+ * Gets the number of lines.
+ *
+ * @return the numberOfLines
+ */
+ public int getNumberOfLines() {
+ checkWidget();
+ return numberOfLines;
+ }
+
+ /**
+ * Sets the number of lines.
+ *
+ * @param numberOfLines the numberOfLines to set
+ */
+ public void setNumberOfLines(final int numberOfLines) {
+ checkWidget();
+ this.numberOfLines = numberOfLines;
+ }
+
+ /**
+ * Adds the listener.
+ *
+ * @param eventType the event type
+ * @param listener the listener
+ * @see org.eclipse.swt.widgets.Text#addListener(int,org.eclipse.swt.widgets.Listener)
+ */
+ @Override
+ public void addListener(final int eventType, final Listener listener) {
+ checkWidget();
+ text.addListener(eventType, listener);
+ }
+
+ /**
+ * Adds the modify listener.
+ *
+ * @param listener the listener
+ * @see org.eclipse.swt.widgets.Text#addModifyListener(org.eclipse.swt.events.ModifyListener)
+ */
+ public void addModifyListener(final ModifyListener listener) {
+ checkWidget();
+ text.addModifyListener(listener);
+ }
+
+ /**
+ * Adds the selection listener.
+ *
+ * @param listener the listener
+ * @see org.eclipse.swt.widgets.Text#addSelectionListener(org.eclipse.swt.events.SelectionListener)
+ */
+ public void addSelectionListener(final SelectionListener listener) {
+ checkWidget();
+ text.addSelectionListener(listener);
+ }
+
+ /**
+ * Adds the verify listener.
+ *
+ * @param listener the listener
+ * @see org.eclipse.swt.widgets.Text#addVerifyListener(org.eclipse.swt.events.VerifyListener)
+ */
+ public void addVerifyListener(final VerifyListener listener) {
+ checkWidget();
+ text.addVerifyListener(listener);
+ }
+
+ /**
+ * Append.
+ *
+ * @param string the string
+ * @see org.eclipse.swt.widgets.Text#append(java.lang.String)
+ */
+ public void append(final String string) {
+ checkWidget();
+ text.append(string);
+ }
+
+ /**
+ * Clear selection.
+ *
+ * @see org.eclipse.swt.widgets.Text#clearSelection()
+ */
+ public void clearSelection() {
+ checkWidget();
+ text.clearSelection();
+ }
+
+ /**
+ * Compute size.
+ *
+ * @param wHint the w hint
+ * @param hHint the h hint
+ * @param changed the changed
+ * @return the point
+ * @see org.eclipse.swt.widgets.Text#computeSize(int, int, boolean)
+ */
+ @Override
+ public Point computeSize(final int wHint, final int hHint, final boolean changed) {
+ checkWidget();
+ return text.computeSize(wHint, hHint, changed);
+ }
+
+ /**
+ * Compute trim.
+ *
+ * @param x the x
+ * @param y the y
+ * @param width the width
+ * @param height the height
+ * @return the rectangle
+ * @see org.eclipse.swt.widgets.Text#computeTrim(int, int, int, int)
+ */
+ @Override
+ public Rectangle computeTrim(final int x, final int y, final int width, final int height) {
+ checkWidget();
+ return super.computeTrim(x, y, width, height);
+ }
+
+ /**
+ * Copy.
+ *
+ * @see org.eclipse.swt.widgets.Text#copy()
+ */
+ public void copy() {
+ checkWidget();
+ text.copy();
+ }
+
+ /**
+ * Cut.
+ *
+ * @see org.eclipse.swt.widgets.Text#cut()
+ */
+ public void cut() {
+ checkWidget();
+ text.cut();
+ }
+
+ /**
+ * Gets the caret line number.
+ *
+ * @return the caret line number
+ * @see org.eclipse.swt.widgets.Text#getCaretLineNumber()
+ */
+ public int getCaretLineNumber() {
+ checkWidget();
+ return text.getCaretLineNumber();
+ }
+
+ /**
+ * Gets the caret location.
+ *
+ * @return the caret location
+ * @see org.eclipse.swt.widgets.Text#getCaretLocation()
+ */
+ public Point getCaretLocation() {
+ checkWidget();
+ return text.getCaretLocation();
+ }
+
+ /**
+ * Gets the caret position.
+ *
+ * @return the caret position
+ * @see org.eclipse.swt.widgets.Text#getCaretPosition()
+ */
+ public int getCaretPosition() {
+ checkWidget();
+ return text.getCaretPosition();
+ }
+
+ /**
+ * Gets the char count.
+ *
+ * @return the char count
+ * @see org.eclipse.swt.widgets.Text#getCharCount()
+ */
+ public int getCharCount() {
+ checkWidget();
+ return text.getCharCount();
+ }
+
+ /**
+ * Gets the double click enabled.
+ *
+ * @return the double click enabled
+ * @see org.eclipse.swt.widgets.Text#getDoubleClickEnabled()
+ */
+ public boolean getDoubleClickEnabled() {
+ checkWidget();
+ return text.getDoubleClickEnabled();
+ }
+
+ /**
+ * Gets the echo char.
+ *
+ * @return the echo char
+ * @see org.eclipse.swt.widgets.Text#getEchoChar()
+ */
+ public char getEchoChar() {
+ checkWidget();
+ return text.getEchoChar();
+ }
+
+ /**
+ * Gets the editable.
+ *
+ * @return the editable
+ * @see org.eclipse.swt.widgets.Text#getEditable()
+ */
+ public boolean getEditable() {
+ checkWidget();
+ return text.getEditable();
+ }
+
+ /**
+ * Gets the enabled.
+ *
+ * @return the enabled
+ * @see org.eclipse.swt.widgets.Control#getEnabled()
+ */
+ @Override
+ public boolean getEnabled() {
+ checkWidget();
+ return super.getEnabled();
+ }
+
+ /**
+ * Gets the line count.
+ *
+ * @return the line count
+ * @see org.eclipse.swt.widgets.Text#getLineCount()
+ */
+ public int getLineCount() {
+ checkWidget();
+ return text.getLineCount();
+ }
+
+ /**
+ * Gets the line delimiter.
+ *
+ * @return the line delimiter
+ * @see org.eclipse.swt.widgets.Text#getLineDelimiter()
+ */
+ public String getLineDelimiter() {
+ checkWidget();
+ return text.getLineDelimiter();
+ }
+
+ /**
+ * Gets the line height.
+ *
+ * @return the line height
+ * @see org.eclipse.swt.widgets.Text#getLineHeight()
+ */
+ public int getLineHeight() {
+ checkWidget();
+ return text.getLineHeight();
+ }
+
+ /**
+ * Gets the message.
+ *
+ * @return the message
+ * @see org.eclipse.swt.widgets.Text#getMessage()
+ */
+ public String getMessage() {
+ checkWidget();
+ return text.getMessage();
+ }
+
+ /**
+ * Gets the orientation.
+ *
+ * @return the orientation
+ * @see org.eclipse.swt.widgets.Text#getOrientation()
+ */
+ public int getOrientation() {
+ checkWidget();
+ return text.getOrientation();
+ }
+
+ /**
+ * Gets the selection.
+ *
+ * @return the selection
+ * @see org.eclipse.swt.widgets.Text#getSelection()
+ */
+ public Point getSelection() {
+ checkWidget();
+ return text.getSelection();
+ }
+
+ /**
+ * Gets the selection count.
+ *
+ * @return the selection count
+ * @see org.eclipse.swt.widgets.Text#getSelectionCount()
+ */
+ public int getSelectionCount() {
+ checkWidget();
+ return text.getSelectionCount();
+ }
+
+ /**
+ * Gets the selection text.
+ *
+ * @return the selection text
+ * @see org.eclipse.swt.widgets.Text#getSelectionText()
+ */
+ public String getSelectionText() {
+ checkWidget();
+ return text.getSelectionText();
+ }
+
+ /**
+ * Gets the tabs.
+ *
+ * @return the tabs
+ * @see org.eclipse.swt.widgets.Text#getTabs()
+ */
+ public int getTabs() {
+ checkWidget();
+ return text.getTabs();
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @return the text
+ * @see org.eclipse.swt.widgets.Text#getText()
+ */
+ public String getText() {
+ checkWidget();
+ return text.getText();
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @param start the start
+ * @param end the end
+ * @return the text
+ * @see org.eclipse.swt.widgets.Text#getText(int, int)
+ */
+ public String getText(final int start, final int end) {
+ checkWidget();
+ return text.getText(start, end);
+ }
+
+ /**
+ * Gets the text limit.
+ *
+ * @return the text limit
+ * @see org.eclipse.swt.widgets.Text#getTextLimit()
+ */
+ public int getTextLimit() {
+ checkWidget();
+ return text.getTextLimit();
+ }
+
+ /**
+ * Gets the top index.
+ *
+ * @return the top index
+ * @see org.eclipse.swt.widgets.Text#getTopIndex()
+ */
+ public int getTopIndex() {
+ checkWidget();
+ return text.getTopIndex();
+ }
+
+ /**
+ * Gets the top pixel.
+ *
+ * @return the top pixel
+ * @see org.eclipse.swt.widgets.Text#getTopPixel()
+ */
+ public int getTopPixel() {
+ checkWidget();
+ return text.getTopPixel();
+ }
+
+ /**
+ * Insert.
+ *
+ * @param string the string
+ * @see org.eclipse.swt.widgets.Text#insert(java.lang.String)
+ */
+ public void insert(final String string) {
+ checkWidget();
+ text.insert(string);
+ }
+
+ /**
+ * Paste.
+ *
+ * @see org.eclipse.swt.widgets.Text#paste()
+ */
+ public void paste() {
+ checkWidget();
+ text.paste();
+ }
+
+ /**
+ * Removes the modify listener.
+ *
+ * @param listener the listener
+ * @see org.eclipse.swt.widgets.Text#removeModifyListener(org.eclipse.swt.events.ModifyListener)
+ */
+ public void removeModifyListener(final ModifyListener listener) {
+ checkWidget();
+ text.removeModifyListener(listener);
+ }
+
+ /**
+ * Removes the selection listener.
+ *
+ * @param listener the listener
+ * @see org.eclipse.swt.widgets.Text#removeSelectionListener(org.eclipse.swt.events.SelectionListener)
+ */
+ public void removeSelectionListener(final SelectionListener listener) {
+ checkWidget();
+ text.removeSelectionListener(listener);
+ }
+
+ /**
+ * Removes the verify listener.
+ *
+ * @param listener the listener
+ * @see org.eclipse.swt.widgets.Text#removeVerifyListener(org.eclipse.swt.events.VerifyListener)
+ */
+ public void removeVerifyListener(final VerifyListener listener) {
+ checkWidget();
+ text.removeVerifyListener(listener);
+ }
+
+ /**
+ * Select all.
+ *
+ * @see org.eclipse.swt.widgets.Text#selectAll()
+ */
+ public void selectAll() {
+ checkWidget();
+ text.selectAll();
+ }
+
+ /**
+ * Sets the double click enabled.
+ *
+ * @param doubleClick the new double click enabled
+ * @see org.eclipse.swt.widgets.Text#setDoubleClickEnabled(boolean)
+ */
+ public void setDoubleClickEnabled(final boolean doubleClick) {
+ checkWidget();
+ text.setDoubleClickEnabled(doubleClick);
+ }
+
+ /**
+ * Sets the echo char.
+ *
+ * @param echo the new echo char
+ * @see org.eclipse.swt.widgets.Text#setEchoChar(char)
+ */
+ public void setEchoChar(final char echo) {
+ checkWidget();
+ text.setEchoChar(echo);
+ }
+
+ /**
+ * Sets the editable.
+ *
+ * @param editable the new editable
+ * @see org.eclipse.swt.widgets.Text#setEditable(boolean)
+ */
+ public void setEditable(final boolean editable) {
+ checkWidget();
+ text.setEditable(editable);
+ }
+
+ /**
+ * Sets the enabled.
+ *
+ * @param value the new enabled
+ * @see org.eclipse.swt.widgets.Text#setEnabled(boolean)
+ */
+ @Override
+ public void setEnabled(final boolean value) {
+ checkWidget();
+ text.setEnabled(value);
+ }
+
+ /**
+ * Sets the font.
+ *
+ * @param font the new font
+ * @see org.eclipse.swt.widgets.Text#setFont(org.eclipse.swt.graphics.Font)
+ */
+ @Override
+ public void setFont(final Font font) {
+ checkWidget();
+ text.setFont(font);
+ table.setFont(font);
+ }
+
+ /**
+ * Sets the foreground.
+ *
+ * @param color the new foreground
+ * @see org.eclipse.swt.widgets.Text#setForeground(org.eclipse.swt.graphics.Color)
+ */
+ @Override
+ public void setForeground(final Color color) {
+ checkWidget();
+ text.setForeground(color);
+ }
+
+ /**
+ * Sets the message.
+ *
+ * @param string the new message
+ * @see org.eclipse.swt.widgets.Text#setMessage(java.lang.String)
+ */
+ public void setMessage(final String string) {
+ checkWidget();
+ text.setMessage(string);
+ }
+
+ /**
+ * Sets the orientation.
+ *
+ * @param orientation the new orientation
+ * @see org.eclipse.swt.widgets.Text#setOrientation(int)
+ */
+ public void setOrientation(final int orientation) {
+ checkWidget();
+ text.setOrientation(orientation);
+ }
+
+ /**
+ * Sets the redraw.
+ *
+ * @param redraw the new redraw
+ * @see org.eclipse.swt.widgets.Text#setRedraw(boolean)
+ */
+ @Override
+ public void setRedraw(final boolean redraw) {
+ checkWidget();
+ text.setRedraw(redraw);
+ }
+
+ /**
+ * Sets the selection.
+ *
+ * @param start the start
+ * @param end the end
+ * @see org.eclipse.swt.widgets.Text#setSelection(int, int)
+ */
+ public void setSelection(final int start, final int end) {
+ checkWidget();
+ text.setSelection(start, end);
+ }
+
+ /**
+ * Sets the selection.
+ *
+ * @param start the new selection
+ * @see org.eclipse.swt.widgets.Text#setSelection(int)
+ */
+ public void setSelection(final int start) {
+ checkWidget();
+ text.setSelection(start);
+ }
+
+ /**
+ * Sets the selection.
+ *
+ * @param selection the new selection
+ * @see org.eclipse.swt.widgets.Text#setSelection(org.eclipse.swt.graphics.Point)
+ */
+ public void setSelection(final Point selection) {
+ checkWidget();
+ text.setSelection(selection);
+ }
+
+ /**
+ * Sets the tabs.
+ *
+ * @param tabs the new tabs
+ * @see org.eclipse.swt.widgets.Text#setTabs(int)
+ */
+ public void setTabs(final int tabs) {
+ checkWidget();
+ text.setTabs(tabs);
+ }
+
+ /**
+ * Sets the text.
+ *
+ * @param text the new text
+ * @see org.eclipse.swt.widgets.Text#setText(java.lang.String)
+ */
+ public void setText(final String text) {
+ checkWidget();
+ this.text.setData(SETTEXT_KEY, Boolean.TRUE);
+ this.text.setText(text);
+ }
+
+ /**
+ * Sets the text limit.
+ *
+ * @param textLimit the new text limit
+ * @see org.eclipse.swt.widgets.Text#setTextLimit(int)
+ */
+ public void setTextLimit(final int textLimit) {
+ checkWidget();
+ text.setTextLimit(textLimit);
+ }
+
+ /**
+ * Sets the top index.
+ *
+ * @param topIndex the new top index
+ * @see org.eclipse.swt.widgets.Text#setTopIndex(int)
+ */
+ public void setTopIndex(final int topIndex) {
+ checkWidget();
+ text.setTopIndex(topIndex);
+ }
+
+ /**
+ * Show selection.
+ *
+ * @see org.eclipse.swt.widgets.Text#showSelection()
+ */
+ public void showSelection() {
+ checkWidget();
+ text.showSelection();
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/textAssist/TextAssistContentProvider.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/textAssist/TextAssistContentProvider.java
new file mode 100644
index 0000000..e009686
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/textAssist/TextAssistContentProvider.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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.textAssist;
+
+import java.util.List;
+
+/**
+ * This class is a content provider for the TextAssist widget. When the user
+ * types something, an instance returns an arraylist of proposition based on the
+ * typed text.
+ */
+public abstract class TextAssistContentProvider {
+
+ /** The text assist. */
+ private TextAssist textAssist;
+
+ /**
+ * Provides the content.
+ *
+ * @param entry text typed by the user
+ * @return an array list of String that contains propositions for the entry
+ * typed by the user
+ */
+ public abstract List<String> getContent(final String entry);
+
+ /**
+ * Sets the text assist.
+ *
+ * @param textAssist the textAssist to set
+ */
+ protected void setTextAssist(final TextAssist textAssist) {
+ this.textAssist = textAssist;
+ }
+
+ /**
+ * Gets the max number of lines.
+ *
+ * @return the max number of propositions.
+ */
+ protected int getMaxNumberOfLines() {
+ return this.textAssist.getNumberOfLines();
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/tipOfTheDay/TipOfTheDay.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/tipOfTheDay/TipOfTheDay.java
new file mode 100644
index 0000000..23aec0c
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/tipOfTheDay/TipOfTheDay.java
@@ -0,0 +1,564 @@
+/*******************************************************************************
+ * 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.tipOfTheDay;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+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.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.header.Header;
+import org.mihalis.opal.utils.ResourceManager;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * Instances of this class are a "Tip of Day" box, which is composed of
+ * <p>
+ * <dl>
+ * <dt><b>A tip</b></dt>
+ * <dt><b>2 buttons to navigate between types</b></dt>
+ * <dt><b>A close button</b></dt>
+ * <dt><b>A checkbox "show tip on startup"</b></dt>
+ * <dd>(optional)</dd>
+ * <dt><b>A checkbox "remember the password"</b></dt>
+ * <dd>(optional)</dd>
+ * </dl>
+ * </p>
+ * .
+ */
+public class TipOfTheDay {
+
+ /** The Constant BLUE_LIGHT_BULB. */
+ private static final String BLUE_LIGHT_BULB = "images/light1.png";
+
+ /** The Constant YELLOW_LIGHT_BULB. */
+ private static final String YELLOW_LIGHT_BULB = "images/light2.png";
+
+ /** The Constant DEFAULT_FONT. */
+ private static final String DEFAULT_FONT = "Arial";
+
+ /**
+ * Types of opal dialog.
+ */
+ public enum TipStyle {
+
+ /** The two columns. */
+ TWO_COLUMNS,
+ /** The two columns large. */
+ TWO_COLUMNS_LARGE,
+ /** The header. */
+ HEADER
+ }
+
+ /** The tips. */
+ private final List<String> tips;
+
+ /** The display show on startup. */
+ private boolean displayShowOnStartup = true;
+
+ /** The show on startup. */
+ private boolean showOnStartup = true;
+
+ /** The shell. */
+ private Shell shell;
+
+ /** The close. */
+ private Button close;
+
+ /** The index. */
+ private int index;
+
+ /** The tip area. */
+ private Browser tipArea;
+
+ /** The font name. */
+ private String fontName;
+
+ /** The style. */
+ private TipStyle style;
+
+ /** The image. */
+ private Image image;
+
+ /**
+ * Constructor.
+ */
+ public TipOfTheDay() {
+ this.tips = new ArrayList<String>();
+ this.index = -1;
+ final Font temp = Display.getDefault().getSystemFont();
+ final FontData[] fontData = temp.getFontData();
+ if (fontData != null && fontData.length > 0) {
+ this.fontName = fontData[0].getName();
+ } else {
+ this.fontName = DEFAULT_FONT;
+ }
+ this.style = TipStyle.TWO_COLUMNS;
+
+ }
+
+ /**
+ * Open the "tip of the day" box.
+ *
+ * @param parent the parent shell
+ */
+ public void open(final Shell parent) {
+ if (this.index == -1) {
+ this.index = new Random().nextInt(this.tips.size());
+ }
+ buildShell(parent);
+ if (this.style == TipStyle.HEADER) {
+ buildHeader();
+ } else {
+ buildLeftColumn();
+ }
+ buildTip();
+ buildButtons();
+ openShell();
+ }
+
+ /**
+ * Build the shell.
+ *
+ * @param parent parent shell
+ */
+ private void buildShell(final Shell parent) {
+ this.shell = new Shell(parent, SWT.SYSTEM_MODAL | SWT.TITLE | SWT.BORDER | SWT.CLOSE | SWT.RESIZE);
+ this.shell.setText(ResourceManager.getLabel(ResourceManager.TIP_OF_THE_DAY));
+ this.shell.setLayout(new GridLayout(this.style == TipStyle.HEADER ? 1 : 2, false));
+
+ this.shell.addListener(SWT.Traverse, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ switch (event.detail) {
+ case SWT.TRAVERSE_ESCAPE:
+ TipOfTheDay.this.shell.dispose();
+ event.detail = SWT.TRAVERSE_NONE;
+ event.doit = false;
+ break;
+ }
+ }
+ });
+ }
+
+ /**
+ * Build the header.
+ */
+ private void buildHeader() {
+ final Header header = new Header(this.shell, SWT.NONE);
+ final GridData gd = new GridData(GridData.FILL, GridData.BEGINNING, true, false);
+ gd.heightHint = 80;
+ header.setLayoutData(gd);
+ header.setTitle(ResourceManager.getLabel(ResourceManager.DID_YOU_KNOW));
+ if (this.image == null) {
+ final Image img = SWTGraphicUtil.createImageFromFile(YELLOW_LIGHT_BULB);
+ header.setImage(img);
+ SWTGraphicUtil.addDisposer(this.shell, img);
+ } else {
+ header.setImage(this.image);
+ }
+ }
+
+ /**
+ * Build the left column.
+ */
+ private void buildLeftColumn() {
+ final Composite composite = new Composite(this.shell, SWT.NONE);
+ int numberOfRows = 1;
+ if (this.style == TipStyle.TWO_COLUMNS_LARGE) {
+ numberOfRows = this.displayShowOnStartup ? 5 : 4;
+ }
+
+ final GridData gd = new GridData(GridData.FILL, GridData.BEGINNING, false, true, 1, numberOfRows);
+ composite.setLayoutData(gd);
+ final FillLayout compositeLayout = new FillLayout();
+ compositeLayout.marginWidth = 2;
+ composite.setLayout(compositeLayout);
+ final Label label = new Label(composite, SWT.NONE);
+ if (this.image == null) {
+ final Image img = SWTGraphicUtil.createImageFromFile(BLUE_LIGHT_BULB);
+ label.setImage(img);
+ SWTGraphicUtil.addDisposer(this.shell, img);
+ } else {
+ label.setImage(this.image);
+ }
+ }
+
+ /**
+ * Build the tip area.
+ */
+ private void buildTip() {
+ if (this.style == TipStyle.TWO_COLUMNS) {
+ final Group group = new Group(this.shell, SWT.NONE);
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true);
+ gd.widthHint = 300;
+ gd.heightHint = 120;
+ group.setLayoutData(gd);
+ group.setText(ResourceManager.getLabel(ResourceManager.DID_YOU_KNOW));
+ final FillLayout fillLayout = new FillLayout();
+ fillLayout.marginWidth = 15;
+ group.setLayout(fillLayout);
+
+ this.tipArea = new Browser(group, SWT.BORDER);
+ } else if (this.style == TipStyle.TWO_COLUMNS_LARGE) {
+ final Label title = new Label(this.shell, SWT.NONE);
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, false);
+ gd.verticalIndent = 15;
+ title.setLayoutData(gd);
+ final Font tempFont = SWTGraphicUtil.buildFontFrom(title, SWT.BOLD, 16);
+ title.setText(ResourceManager.getLabel(ResourceManager.TIP_OF_THE_DAY));
+ title.setFont(tempFont);
+ SWTGraphicUtil.addDisposer(this.shell, tempFont);
+
+ final Label separator = new Label(this.shell, SWT.SEPARATOR | SWT.HORIZONTAL);
+ separator.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+
+ this.tipArea = new Browser(this.shell, SWT.BORDER);
+ final GridData gdTipArea = new GridData(GridData.FILL, GridData.FILL, true, true);
+ gdTipArea.heightHint = 120;
+ this.tipArea.setLayoutData(gdTipArea);
+
+ } else {
+ this.tipArea = new Browser(this.shell, SWT.BORDER);
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true);
+ gd.heightHint = 120;
+ this.tipArea.setLayoutData(gd);
+ }
+ fillTipArea();
+
+ }
+
+ /**
+ * Fill the tip area with the selected tip.
+ */
+ private void fillTipArea() {
+ this.tipArea.setText("<html><body bgcolor=\"#ffffff\" text=\"#000000\"><p style=\"font-family:" + //
+ this.fontName + //
+ ";font-size=12px\">" + //
+ this.tips.get(this.index) + //
+ "</p></body></html>");
+ }
+
+ /**
+ * Build the button (checkbox, previous tip, next tip, close).
+ */
+ private void buildButtons() {
+ final Composite composite = new Composite(this.shell, SWT.NONE);
+ int numberOfColumns;
+ if (this.style == TipStyle.HEADER) {
+ numberOfColumns = 1;
+ } else if (this.style == TipStyle.TWO_COLUMNS) {
+ numberOfColumns = 2;
+ } else {
+ numberOfColumns = 1;
+ }
+
+ final GridData gd = new GridData(GridData.FILL, GridData.BEGINNING, false, false, numberOfColumns, 1);
+ composite.setLayoutData(gd);
+ final GridLayout gridLayout = new GridLayout();
+ gridLayout.marginWidth = 2;
+ if (this.style == TipStyle.TWO_COLUMNS_LARGE) {
+ composite.setLayout(new GridLayout(3, false));
+ } else {
+ composite.setLayout(new GridLayout(this.displayShowOnStartup ? 4 : 3, false));
+ }
+
+ final GridData gridShowOnStartup, gridPrevious, gridNext, gridClose;
+ if (this.style == TipStyle.TWO_COLUMNS_LARGE) {
+ gridShowOnStartup = new GridData(GridData.BEGINNING, GridData.BEGINNING, true, false, 3, 1);
+
+ gridPrevious = new GridData(GridData.END, GridData.CENTER, true, false);
+ gridPrevious.widthHint = 120;
+
+ gridNext = new GridData(GridData.CENTER, GridData.CENTER, false, false);
+ gridNext.widthHint = 120;
+
+ gridClose = new GridData(GridData.BEGINNING, GridData.CENTER, true, false);
+ gridClose.widthHint = 120;
+
+ } else {
+ gridShowOnStartup = new GridData(GridData.BEGINNING, GridData.CENTER, true, false);
+
+ gridPrevious = new GridData(GridData.END, GridData.CENTER, this.showOnStartup ? false : true, false);
+ gridPrevious.widthHint = 120;
+
+ gridNext = new GridData(GridData.FILL, GridData.CENTER, false, false);
+ gridNext.widthHint = 120;
+
+ gridClose = new GridData(GridData.FILL, GridData.CENTER, false, false);
+ gridClose.widthHint = 120;
+ }
+
+ if (this.displayShowOnStartup) {
+ buildShowOnStartup(composite, gridShowOnStartup);
+ }
+
+ buildPreviousButton(composite, gridPrevious);
+ buildNextButton(composite, gridNext);
+ buildCloseButton(composite, gridClose);
+
+ }
+
+ /**
+ * Build the "show on startup" checkbox.
+ *
+ * @param composite parent composite
+ * @param gridData associated grid data
+ */
+ private void buildShowOnStartup(final Composite composite, final GridData gridData) {
+ final Button checkBox = new Button(composite, SWT.CHECK);
+ checkBox.setLayoutData(gridData);
+ checkBox.setText(ResourceManager.getLabel(ResourceManager.SHOW_TIP_AT_STARTUP));
+ checkBox.setSelection(this.showOnStartup);
+ checkBox.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ TipOfTheDay.this.showOnStartup = checkBox.getSelection();
+ }
+ });
+
+ }
+
+ /**
+ * Build the "previous tip" button.
+ *
+ * @param composite parent composite
+ * @param gridData associated grid data
+ */
+ private void buildPreviousButton(final Composite composite, final GridData gridData) {
+ final Button previous = new Button(composite, SWT.PUSH);
+ previous.setText(ResourceManager.getLabel(ResourceManager.PREVIOUS_TIP));
+ previous.setLayoutData(gridData);
+ previous.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ if (TipOfTheDay.this.index == 0) {
+ setIndex(TipOfTheDay.this.tips.size() - 1);
+ } else {
+ setIndex(TipOfTheDay.this.index - 1);
+ }
+ }
+
+ });
+
+ }
+
+ /**
+ * Build the "next tip" button.
+ *
+ * @param composite parent composite
+ * @param gridData associated grid data
+ */
+ private void buildNextButton(final Composite composite, final GridData gridData) {
+ final Button next = new Button(composite, SWT.PUSH);
+ next.setText(ResourceManager.getLabel(ResourceManager.NEXT_TIP));
+
+ next.setLayoutData(gridData);
+ next.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ if (TipOfTheDay.this.index == TipOfTheDay.this.tips.size() - 1) {
+ setIndex(0);
+ } else {
+ setIndex(TipOfTheDay.this.index + 1);
+ }
+ }
+
+ });
+ }
+
+ /**
+ * Build the "close" button.
+ *
+ * @param composite parent composite
+ * @param gridData associated grid data
+ */
+ private void buildCloseButton(final Composite composite, final GridData gridData) {
+ this.close = new Button(composite, SWT.PUSH);
+ this.close.setText(ResourceManager.getLabel(ResourceManager.CLOSE));
+
+ this.close.setLayoutData(gridData);
+ this.close.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ TipOfTheDay.this.shell.dispose();
+ }
+
+ });
+
+ }
+
+ /**
+ * Open the shell.
+ */
+ private void openShell() {
+ this.shell.setDefaultButton(this.close);
+ this.shell.pack();
+ this.shell.open();
+ SWTGraphicUtil.centerShell(this.shell);
+
+ while (!this.shell.isDisposed()) {
+ if (!this.shell.getDisplay().readAndDispatch()) {
+ this.shell.getDisplay().sleep();
+ }
+ }
+
+ }
+
+ /**
+ * Add a tip.
+ *
+ * @param tip tip to add
+ * @return the current object
+ */
+ public TipOfTheDay addTip(final String tip) {
+ this.tips.add(tip);
+ return this;
+ }
+
+ /**
+ * Gets the image.
+ *
+ * @return the image
+ */
+ public Image getImage() {
+ return this.image;
+ }
+
+ /**
+ * Gets the index.
+ *
+ * @return the index of the current tip
+ */
+ public int getIndex() {
+ return this.index;
+ }
+
+ /**
+ * Gets the style.
+ *
+ * @return the style of the window
+ */
+ public TipStyle getStyle() {
+ return this.style;
+ }
+
+ /**
+ * Gets the tips.
+ *
+ * @return all the the tips
+ */
+ public List<String> getTips() {
+ return this.tips;
+ }
+
+ /**
+ * Checks if is display show on startup.
+ *
+ * @return if <code>true</code>, the "Show On Startup" checkbox is displayed
+ */
+ public boolean isDisplayShowOnStartup() {
+ return this.displayShowOnStartup;
+ }
+
+ /**
+ * Checks if is show on startup.
+ *
+ * @return the value of the checkbox "Show On Startup"
+ */
+ public boolean isShowOnStartup() {
+ return this.showOnStartup;
+ }
+
+ /**
+ * Sets the display show on startup.
+ *
+ * @param displayShowOnStartup the new display show on startup
+ */
+ public void setDisplayShowOnStartup(final boolean displayShowOnStartup) {
+ this.displayShowOnStartup = displayShowOnStartup;
+ }
+
+ /**
+ * Sets the index.
+ *
+ * @param index the index of the selected tip. By default, the tip is chosen
+ * randomly
+ */
+ public void setIndex(final int index) {
+ if (index < 0 || index >= this.tips.size() || this.tips.get(index) == null) {
+ throw new IllegalArgumentException("Index should be between 0 and " + (this.tips.size() - 1) + " (entered value:" + index + ")");
+ }
+
+ this.index = index;
+ if (this.tipArea != null && !this.tipArea.isDisposed()) {
+ fillTipArea();
+ }
+ }
+
+ /**
+ * Sets the image.
+ *
+ * @param image the image to set
+ */
+ public void setImage(final Image image) {
+ this.image = image;
+ }
+
+ /**
+ * Sets the show on startup.
+ *
+ * @param showOnStartup the new show on startup
+ */
+ public void setShowOnStartup(final boolean showOnStartup) {
+ this.showOnStartup = showOnStartup;
+ }
+
+ /**
+ * Sets the style.
+ *
+ * @param style the style of the window
+ */
+ public void setStyle(final TipStyle style) {
+ this.style = style;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/titledSeparator/TitledSeparator.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/titledSeparator/TitledSeparator.java
new file mode 100644
index 0000000..1f44b68
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/titledSeparator/TitledSeparator.java
@@ -0,0 +1,316 @@
+/*******************************************************************************
+ * 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.titledSeparator;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+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.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 separator with a title and/or an image.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * </p>
+ */
+public class TitledSeparator extends Composite {
+
+ /** The alignment. */
+ private int alignment;
+
+ /** The image. */
+ private Image image;
+
+ /** The text. */
+ private String text;
+
+ /**
+ * 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 TitledSeparator(final Composite parent, final int style) {
+ super(parent, style);
+ this.alignment = SWT.LEFT;
+
+ final Color originalColor = new Color(getDisplay(), 0, 88, 150);
+ setForeground(originalColor);
+
+ final Font originalFont;
+ final FontData[] fontData = getFont().getFontData();
+ if (fontData != null && fontData.length > 0) {
+ final FontData fd = fontData[0];
+ fd.setStyle(SWT.BOLD);
+ originalFont = new Font(getDisplay(), fd);
+ setFont(originalFont);
+ } else {
+ originalFont = null;
+ }
+
+ this.addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ redrawComposite();
+ }
+ });
+
+ SWTGraphicUtil.addDisposer(this, originalColor);
+ SWTGraphicUtil.addDisposer(this, originalFont);
+ }
+
+ /**
+ * Redraw the composite.
+ */
+ private void redrawComposite() {
+ // Dispose previous content
+ for (final Control c : this.getChildren()) {
+ c.dispose();
+ }
+
+ int numberOfColumns = 1;
+
+ if (this.text != null) {
+ numberOfColumns++;
+ }
+
+ if (this.image != null) {
+ numberOfColumns++;
+ }
+
+ if (this.alignment == SWT.CENTER) {
+ numberOfColumns++;
+ }
+
+ super.setLayout(new GridLayout(numberOfColumns, false));
+ createContent();
+ }
+
+ /**
+ * Create the content.
+ */
+ private void createContent() {
+ switch (this.alignment) {
+ case SWT.CENTER:
+ createSeparator();
+ createTitle();
+ createSeparator();
+ break;
+ case SWT.LEFT:
+ createTitle();
+ createSeparator();
+ break;
+ default:
+ createSeparator();
+ createTitle();
+ break;
+ }
+ }
+
+ /**
+ * Create a separator.
+ */
+ private void createSeparator() {
+ final Label separator = new Label(this, SWT.SEPARATOR | SWT.HORIZONTAL);
+ separator.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ separator.setBackground(getBackground());
+ }
+
+ /**
+ * Create the title.
+ */
+ private void createTitle() {
+ if (this.image != null) {
+ final Label imageLabel = createLabel();
+ imageLabel.setImage(this.image);
+ }
+
+ if (this.text != null && !this.text.trim().equals("")) {
+ final Label textLabel = createLabel();
+ textLabel.setText(this.text);
+
+ }
+ }
+
+ /**
+ * Creates the label.
+ *
+ * @return a SWT label
+ */
+ private Label createLabel() {
+ final Label label = new Label(this, SWT.NONE);
+ label.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false));
+ label.setFont(getFont());
+ label.setForeground(getForeground());
+ label.setBackground(getBackground());
+ return label;
+ }
+
+ /**
+ * 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");
+ }
+
+ /**
+ * Returns a value which describes the position of the text or image 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 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 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;
+ }
+
+ /**
+ * 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 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 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;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/DownUpAppearTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/DownUpAppearTransition.java
new file mode 100644
index 0000000..08e7178
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/DownUpAppearTransition.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+/**
+ * In this transition, the second control is behind, the first control is
+ * sliding from down to up.
+ */
+public class DownUpAppearTransition extends VerticalTransition {
+
+ /**
+ * Gets the coeff.
+ *
+ * @return the coeff
+ * @see org.mihalis.opal.transitionComposite.VerticalTransition#getCoeff()
+ */
+ @Override
+ protected int getCoeff() {
+ return -1;
+ }
+
+ /**
+ * Second is behind.
+ *
+ * @return true, if successful
+ * @see org.mihalis.opal.transitionComposite.VerticalTransition#secondIsBehind()
+ */
+ @Override
+ protected boolean secondIsBehind() {
+ return false;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/DownUpTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/DownUpTransition.java
new file mode 100644
index 0000000..635c51e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/DownUpTransition.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+/**
+ * In this transition, both control are sliding (vertical movement, down to up).
+ */
+public class DownUpTransition extends VerticalTransition {
+
+ /**
+ * Gets the coeff.
+ *
+ * @return the coeff
+ * @see org.mihalis.opal.transitionComposite.VerticalTransition#getCoeff()
+ */
+ @Override
+ protected int getCoeff() {
+ return -1;
+ }
+
+ /**
+ * Second is behind.
+ *
+ * @return true, if successful
+ * @see org.mihalis.opal.transitionComposite.VerticalTransition#secondIsBehind()
+ */
+ @Override
+ protected boolean secondIsBehind() {
+ return true;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/HorizontalTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/HorizontalTransition.java
new file mode 100644
index 0000000..5a766a4
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/HorizontalTransition.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Instances of this class are horizontal transitions (right>left,
+ * left>right...)
+ */
+public abstract class HorizontalTransition implements Transition {
+
+ /**
+ * Perform transition.
+ *
+ * @param first the first
+ * @param second the second
+ * @see org.mihalis.opal.transitionComposite.Transition#performTransition(org.eclipse.swt.widgets.Control,
+ * org.eclipse.swt.widgets.Control)
+ */
+ @Override
+ public void performTransition(final Control first, final Control second) {
+ if (first.isDisposed() || second.isDisposed()) {
+ return;
+ }
+
+ final int[] currentPosition = new int[1];
+ currentPosition[0] = 0;
+ final int maxValue = first.getParent().getClientArea().width;
+
+ first.setBounds(0, 0, first.getBounds().width, first.getBounds().height);
+ second.setBounds(0, -1 * second.getBounds().width, second.getBounds().width, second.getBounds().height);
+
+ first.moveAbove(second);
+ second.setVisible(true);
+
+ if (first.isDisposed() || first.getDisplay().isDisposed()) {
+ return;
+ }
+ first.getDisplay().timerExec(0, new Runnable() {
+
+ @Override
+ public void run() {
+
+ if (first.isDisposed() || second.isDisposed()) {
+ return;
+ }
+
+ currentPosition[0] = currentPosition[0] + 10;
+ if (currentPosition[0] > maxValue) {
+ first.setVisible(false);
+ second.setVisible(true);
+ second.setBounds(0, 0, first.getBounds().width, first.getBounds().height);
+ return;
+ }
+
+ first.setBounds(getCoeff() * currentPosition[0], 0, first.getBounds().width, first.getBounds().height);
+
+ if (secondIsBehind()) {
+ second.setBounds(-1 * getCoeff() * (maxValue - currentPosition[0]), 0, second.getBounds().width, second.getBounds().height);
+ }
+
+ if (!first.isDisposed() && !first.getDisplay().isDisposed()) {
+ first.getDisplay().timerExec(10, this);
+ }
+ }
+
+ });
+
+ }
+
+ /**
+ * Gets the coeff.
+ *
+ * @return the multiplicator coefficient
+ */
+ protected abstract int getCoeff();
+
+ /**
+ * Second is behind.
+ *
+ * @return <code>true</code> if the second composite is behind the first
+ * one, <code>false</code> otherwise
+ */
+ protected abstract boolean secondIsBehind();
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/LeftRightAppearTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/LeftRightAppearTransition.java
new file mode 100644
index 0000000..266a230
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/LeftRightAppearTransition.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+/**
+ * In this transition, the second control is behind, the first control is
+ * sliding from left to right.
+ */
+public class LeftRightAppearTransition extends HorizontalTransition {
+
+ /**
+ * Gets the coeff.
+ *
+ * @return the coeff
+ * @see org.mihalis.opal.transitionComposite.HorizontalTransition#getCoeff()
+ */
+ @Override
+ protected int getCoeff() {
+ return 1;
+ }
+
+ /**
+ * Second is behind.
+ *
+ * @return true, if successful
+ * @see org.mihalis.opal.transitionComposite.HorizontalTransition#secondIsBehind()
+ */
+ @Override
+ protected boolean secondIsBehind() {
+ return false;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/LeftRightTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/LeftRightTransition.java
new file mode 100644
index 0000000..0bb1354
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/LeftRightTransition.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+/**
+ * In this transition, both control are sliding (vertical movement, left to
+ * right).
+ */
+public class LeftRightTransition extends HorizontalTransition {
+
+ /**
+ * Gets the coeff.
+ *
+ * @return the coeff
+ * @see org.mihalis.opal.transitionComposite.HorizontalTransition#getCoeff()
+ */
+ @Override
+ protected int getCoeff() {
+ return 1;
+ }
+
+ /**
+ * Second is behind.
+ *
+ * @return true, if successful
+ * @see org.mihalis.opal.transitionComposite.HorizontalTransition#secondIsBehind()
+ */
+ @Override
+ protected boolean secondIsBehind() {
+ return true;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/NoTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/NoTransition.java
new file mode 100644
index 0000000..4b50b9b
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/NoTransition.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * This transition is simple, because there is no effect :).
+ */
+class NoTransition implements Transition {
+
+ /**
+ * Perform transition.
+ *
+ * @param first the first
+ * @param second the second
+ * @see org.mihalis.opal.transitionComposite.Transition#performTransition(org.eclipse.swt.widgets.Control,
+ * org.eclipse.swt.widgets.Control)
+ */
+ @Override
+ public void performTransition(final Control first, final Control second) {
+ first.setVisible(false);
+ second.setVisible(true);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/RightLeftAppearTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/RightLeftAppearTransition.java
new file mode 100644
index 0000000..15ebd6d
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/RightLeftAppearTransition.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+/**
+ * In this transition, the second control is behind, the first control is
+ * sliding from right to left.
+ */
+public class RightLeftAppearTransition extends HorizontalTransition {
+
+ /**
+ * Gets the coeff.
+ *
+ * @return the coeff
+ * @see org.mihalis.opal.transitionComposite.HorizontalTransition#getCoeff()
+ */
+ @Override
+ protected int getCoeff() {
+ return -1;
+ }
+
+ /**
+ * Second is behind.
+ *
+ * @return true, if successful
+ * @see org.mihalis.opal.transitionComposite.HorizontalTransition#secondIsBehind()
+ */
+ @Override
+ protected boolean secondIsBehind() {
+ return false;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/RightLeftTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/RightLeftTransition.java
new file mode 100644
index 0000000..523743b
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/RightLeftTransition.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+/**
+ * In this transition, both control are sliding (vertical movement, right to
+ * left).
+ */
+public class RightLeftTransition extends HorizontalTransition {
+
+ /**
+ * Gets the coeff.
+ *
+ * @return the coeff
+ * @see org.mihalis.opal.transitionComposite.HorizontalTransition#getCoeff()
+ */
+ @Override
+ protected int getCoeff() {
+ return -1;
+ }
+
+ /**
+ * Second is behind.
+ *
+ * @return true, if successful
+ * @see org.mihalis.opal.transitionComposite.HorizontalTransition#secondIsBehind()
+ */
+ @Override
+ protected boolean secondIsBehind() {
+ return true;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TRANSITIONS.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TRANSITIONS.java
new file mode 100644
index 0000000..50097b0
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TRANSITIONS.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+/**
+ * This enumeration is a list of transitions.
+ */
+public enum TRANSITIONS {
+
+ /** The left to right. */
+ LEFT_TO_RIGHT,
+ /** The left to right and appear. */
+ LEFT_TO_RIGHT_AND_APPEAR,
+ /** The right to left. */
+ RIGHT_TO_LEFT,
+ /** The right to left and appear. */
+ RIGHT_TO_LEFT_AND_APPEAR,
+ /** The up to down. */
+ UP_TO_DOWN,
+ /** The up to down and appear. */
+ UP_TO_DOWN_AND_APPEAR,
+ /** The down to up. */
+ DOWN_TO_UP,
+ /** The down to up and appear. */
+ DOWN_TO_UP_AND_APPEAR,
+ /** The none. */
+ NONE
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/Transition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/Transition.java
new file mode 100644
index 0000000..89df3ec
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/Transition.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * This interface describes a transition.
+ */
+interface Transition {
+
+ /**
+ * Performs a transition between 2 controls of a TransitionComposite.
+ *
+ * @param first first control
+ * @param second second control
+ */
+ void performTransition(Control first, Control second);
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TransitionComposite.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TransitionComposite.java
new file mode 100644
index 0000000..e0a2b04
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TransitionComposite.java
@@ -0,0 +1,285 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+/**
+ * Instances of this class provide a multi-part composite. You can perform transitions when you move from one part to another
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>BORDER</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * </p>
+ */
+public class TransitionComposite extends Composite {
+
+ /** The controls. */
+ private final List<Control> controls;
+
+ /** The selection. */
+ private int selection = 0;
+
+ /** The transition. */
+ private TRANSITIONS transition = TRANSITIONS.NONE;
+
+ /**
+ * 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 TransitionComposite(final Composite parent, final int style) {
+ super(parent, style);
+ this.controls = new ArrayList<Control>();
+
+ addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event e) {
+ TransitionComposite.this.controls.get(TransitionComposite.this.selection).setBounds(getClientArea());
+ }
+ });
+ }
+
+ /**
+ * Add a control to this composite.
+ *
+ * @param control control to add
+ * @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 addControl(final Control control) {
+ checkWidget();
+ if (!control.isDisposed()) {
+ this.controls.add(control);
+
+ if (this.controls.size() == 1) {
+ control.setVisible(true);
+ } else {
+ control.setVisible(false);
+ }
+
+ control.addListener(SWT.Dispose, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ TransitionComposite.this.controls.remove(event.widget);
+ }
+ });
+ }
+ }
+
+ /**
+ * 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 = 0, height = 0;
+ for (final Control control : this.controls) {
+ final Point point = control.computeSize(wHint, hHint, changed);
+ width = Math.max(width, point.x);
+ height = Math.max(height, point.y);
+ }
+ return new Point(Math.max(width, wHint), Math.max(height, hHint));
+ }
+
+ /**
+ * Gets the transition.
+ *
+ * @return the current transition
+ * @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 TRANSITIONS getTransition() {
+ checkWidget();
+ return this.transition;
+ }
+
+ /**
+ * Move selection to the first control.
+ *
+ * @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 moveToFirst() {
+ checkWidget();
+ changeSelectionTo(0);
+ }
+
+ /**
+ * Move selection to the last control.
+ *
+ * @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 moveToLast() {
+ checkWidget();
+ changeSelectionTo(this.controls.size() - 1);
+ }
+
+ /**
+ * Move selection to the next control.
+ *
+ * @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 moveToNext() {
+ checkWidget();
+ final int index = this.selection + 1;
+ if (index == this.controls.size()) {
+ return;
+ }
+ changeSelectionTo(index);
+ }
+
+ /**
+ * Move selection to the previous control.
+ *
+ * @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 moveToPrevious() {
+ checkWidget();
+ final int index = this.selection - 1;
+ if (index < 0) {
+ return;
+ }
+ changeSelectionTo(index);
+ }
+
+ /**
+ * Move selection to a given index.
+ *
+ * @param index index of 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(final int index) {
+ checkWidget();
+ if (index < 0 || index > this.controls.size() - 1) {
+ return;
+ }
+ changeSelectionTo(index);
+ }
+
+ /**
+ * Change current selection.
+ *
+ * @param index index of the new selection
+ */
+ private void changeSelectionTo(final int index) {
+
+ final Transition t = TransitionFactory.getTransitionFor(this.transition);
+ t.performTransition(this.controls.get(this.selection), this.controls.get(index));
+
+ this.selection = index;
+ this.controls.get(this.selection).setBounds(getClientArea());
+ }
+
+ /**
+ * Move selection to a given control.
+ *
+ * @param control control newly 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 void setSelection(final Control control) {
+ checkWidget();
+ for (int i = 0; i < this.controls.size(); i++) {
+ if (this.controls.get(i) != null && this.controls.get(i).equals(control)) {
+ changeSelectionTo(i);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Move selection to the first control.
+ *
+ * @param transition new transition
+ * @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 setTransition(final TRANSITIONS transition) {
+ checkWidget();
+ this.transition = transition;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TransitionFactory.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TransitionFactory.java
new file mode 100644
index 0000000..b594ae6
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/TransitionFactory.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+/**
+ * This class is a transition factory.
+ */
+public class TransitionFactory {
+
+ /**
+ * Gets the transition for.
+ *
+ * @param transition transition to get
+ * @return a transition corresponding to the <code>transition</code>
+ * parameter
+ */
+ public static Transition getTransitionFor(final TRANSITIONS transition) {
+ switch (transition) {
+ case DOWN_TO_UP:
+ return new DownUpTransition();
+ case DOWN_TO_UP_AND_APPEAR:
+ return new DownUpAppearTransition();
+ case LEFT_TO_RIGHT:
+ return new LeftRightTransition();
+ case LEFT_TO_RIGHT_AND_APPEAR:
+ return new LeftRightAppearTransition();
+ case NONE:
+ return new NoTransition();
+ case RIGHT_TO_LEFT:
+ return new RightLeftTransition();
+ case RIGHT_TO_LEFT_AND_APPEAR:
+ return new RightLeftAppearTransition();
+ case UP_TO_DOWN:
+ return new UpDownTransition();
+ case UP_TO_DOWN_AND_APPEAR:
+ return new UpDownAppearTransition();
+ }
+ return null;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/UpDownAppearTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/UpDownAppearTransition.java
new file mode 100644
index 0000000..1a59934
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/UpDownAppearTransition.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+/**
+ * In this transition, the second control is behind, the first control is
+ * sliding from up to down.
+ */
+public class UpDownAppearTransition extends VerticalTransition {
+
+ /**
+ * Gets the coeff.
+ *
+ * @return the coeff
+ * @see org.mihalis.opal.transitionComposite.VerticalTransition#getCoeff()
+ */
+ @Override
+ protected int getCoeff() {
+ return 1;
+ }
+
+ /**
+ * Second is behind.
+ *
+ * @return true, if successful
+ * @see org.mihalis.opal.transitionComposite.VerticalTransition#secondIsBehind()
+ */
+ @Override
+ protected boolean secondIsBehind() {
+ return false;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/UpDownTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/UpDownTransition.java
new file mode 100644
index 0000000..b53c6df
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/UpDownTransition.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+/**
+ * In this transition, both control are sliding (vertical movement, up to down).
+ */
+public class UpDownTransition extends VerticalTransition {
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.transitionComposite.VerticalTransition#getCoeff()
+ */
+ @Override
+ protected int getCoeff() {
+ return 1;
+ }
+
+ /* (non-Javadoc)
+ * @see org.mihalis.opal.transitionComposite.VerticalTransition#secondIsBehind()
+ */
+ @Override
+ protected boolean secondIsBehind() {
+ return true;
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/VerticalTransition.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/VerticalTransition.java
new file mode 100644
index 0000000..7a79b2d
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/transitionComposite/VerticalTransition.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Instances of this class are vertical transitions (down>up, up>down...)
+ */
+abstract class VerticalTransition implements Transition {
+
+ /**
+ * Perform transition.
+ *
+ * @param first the first
+ * @param second the second
+ * @see org.mihalis.opal.transitionComposite.Transition#performTransition(org.eclipse.swt.widgets.Control,
+ * org.eclipse.swt.widgets.Control)
+ */
+ @Override
+ public void performTransition(final Control first, final Control second) {
+ if (first.isDisposed() || second.isDisposed()) {
+ return;
+ }
+
+ final int[] currentPosition = new int[1];
+ currentPosition[0] = 0;
+ final int maxValue = first.getParent().getClientArea().height;
+
+ first.setBounds(0, 0, first.getBounds().width, first.getBounds().height);
+ second.setBounds(0, -1 * second.getBounds().width, second.getBounds().width, second.getBounds().height);
+
+ first.moveAbove(second);
+ second.setVisible(true);
+
+ if (first.isDisposed() || first.getDisplay().isDisposed()) {
+ return;
+ }
+
+ first.getDisplay().timerExec(0, new Runnable() {
+
+ @Override
+ public void run() {
+
+ if (first.isDisposed() || second.isDisposed()) {
+ return;
+ }
+
+ currentPosition[0] = currentPosition[0] + 10;
+ if (currentPosition[0] > maxValue) {
+ first.setVisible(false);
+ second.setBounds(0, 0, first.getBounds().width, first.getBounds().height);
+
+ return;
+ }
+
+ first.setBounds(0, getCoeff() * currentPosition[0], first.getBounds().width, first.getBounds().height);
+ if (secondIsBehind()) {
+ second.setBounds(0, -1 * getCoeff() * (maxValue - currentPosition[0]), second.getBounds().width, second.getBounds().height);
+ }
+ if (!first.isDisposed() && !first.getDisplay().isDisposed()) {
+ first.getDisplay().timerExec(15, this);
+ }
+ }
+
+ });
+
+ }
+
+ /**
+ * Gets the coeff.
+ *
+ * @return the multiplicator coefficient
+ */
+ protected abstract int getCoeff();
+
+ /**
+ * Second is behind.
+ *
+ * @return <code>true</code> if the second composite is behind the first
+ * one, <code>false</code> otherwise
+ */
+ protected abstract boolean secondIsBehind();
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/AdvancedPath.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/AdvancedPath.java
new file mode 100644
index 0000000..2fb810a
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/AdvancedPath.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * 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:
+ * Waldimiro Rossi - addRoundRectangle and addCircle methods
+ * Laurent CARON (laurent.caron at gmail dot com) - initial API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.utils;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.Path;
+
+/**
+ * AdvancedPath, a Path object that contains extra paths.
+ *
+ * @see Path
+ */
+public class AdvancedPath extends Path {
+
+ /**
+ * Contructor.
+ *
+ * @param device the device
+ */
+ public AdvancedPath(final Device device) {
+ super(device);
+ }
+
+ /**
+ * Adds to the receiver the circle specified by x, y, radius.
+ *
+ * @param x the x coordinate of the rectangle to add
+ * @param y the y coordinate of the rectangle to add
+ * @param radius the width of the radius
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been
+ * disposed</li>
+ * </ul>
+ */
+ public void addCircle(final float x, final float y, final float radius) {
+ if (this.isDisposed()) {
+ SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ }
+ this.addArc(x, y, radius, radius, 0, 360);
+ }
+
+ /**
+ * Adds to the receiver the round-cornered rectangle specified by x, y, width and height.
+ *
+ * @param x the x coordinate of the rectangle to add
+ * @param y the y coordinate of the rectangle to add
+ * @param width the width of the rectangle to add
+ * @param height the height of the rectangle to add
+ * @param arcWidth the width of the arc
+ * @param arcHeight the height of the arc
+ * @exception SWTException
+ * <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+ public void addRoundRectangle(final float x, final float y, final float width, final float height, final float arcWidth, final float arcHeight) {
+ if (this.isDisposed()) {
+ SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ }
+
+ // Top left corner
+ this.cubicTo(x, y, x, y, x, y + arcHeight);
+ this.cubicTo(x, y, x, y, x + arcWidth, y);
+
+ // Top right corner
+ this.cubicTo(x + width, y, x + width, y, x + width - arcWidth, y);
+ this.cubicTo(x + width, y, x + width, y, x + width, y + arcHeight);
+
+ // Bottom right corner
+ this.cubicTo(x + width, y + height, x + width, y + height, x + width, y + height - arcHeight);
+ this.cubicTo(x + width, y + height, x + width, y + height, x + width - arcWidth, y + height);
+
+ // Bottom left corner
+ this.cubicTo(x, y + height, x, y + height, x + arcWidth, y + height);
+ this.cubicTo(x, y + height, x, y + height, x, y + height - arcHeight);
+ }
+
+ /**
+ * Adds to the receiver the rectangle specified by x, y, width and height.<br/>
+ * This rectangle is round-cornered on the left, and straight on the right.
+ *
+ * @param x the x coordinate of the rectangle to add
+ * @param y the y coordinate of the rectangle to add
+ * @param width the width of the rectangle to add
+ * @param height the height of the rectangle to add
+ * @param arcWidth the width of the arc
+ * @param arcHeight the height of the arc
+ * @exception SWTException
+ * <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+ public void addRoundRectangleStraightRight(final float x, final float y, final float width, final float height, final float arcWidth, final float arcHeight) {
+ if (this.isDisposed()) {
+ SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ }
+
+ // Top left corner
+ this.cubicTo(x, y, x, y, x, y + arcHeight);
+ this.cubicTo(x, y, x, y, x + arcWidth, y);
+
+ // Top right corner
+ this.lineTo(x + width, y);
+
+ // Bottom right corner
+ this.lineTo(x + width, y + height);
+
+ // Bottom left corner
+ this.cubicTo(x, y + height, x, y + height, x + arcWidth, y + height);
+ this.cubicTo(x, y + height, x, y + height, x, y + height - arcHeight);
+ }
+
+ /**
+ * Adds to the receiver the rectangle specified by x, y, width and height.<br/>
+ * This rectangle is round-cornered on the right, and straight on the left.
+ *
+ * @param x the x coordinate of the rectangle to add
+ * @param y the y coordinate of the rectangle to add
+ * @param width the width of the rectangle to add
+ * @param height the height of the rectangle to add
+ * @param arcWidth the width of the arc
+ * @param arcHeight the height of the arc
+ * @exception SWTException
+ * <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+ public void addRoundRectangleStraightLeft(final float x, final float y, final float width, final float height, final float arcWidth, final float arcHeight) {
+ if (this.isDisposed()) {
+ SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ }
+
+ // Top left corner
+ moveTo(x, y);
+ lineTo(x + width - arcWidth, y);
+
+ // Top right corner
+ this.cubicTo(x + width, y, x + width, y, x + width - arcWidth, y);
+ this.cubicTo(x + width, y, x + width, y, x + width, y + arcHeight);
+
+ // Bottom right corner
+ this.cubicTo(x + width, y + height, x + width, y + height, x + width, y + height - arcHeight);
+ this.cubicTo(x + width, y + height, x + width, y + height, x + width - arcWidth, y + height);
+
+ // Bottom left corner
+ lineTo(x, y + height);
+ lineTo(x, y);
+ }
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/FileToolbox.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/FileToolbox.java
new file mode 100644
index 0000000..fd0829b
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/FileToolbox.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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.utils;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * The Class FileToolbox.
+ */
+public class FileToolbox {
+
+ /**
+ * Loads a file into a stream.
+ *
+ * @param fileName file name
+ * @return a stream composed of this file
+ */
+ public static InputStream getInputStream(final String fileName) {
+ if (fileName.startsWith("jar:")) {
+ URL url;
+ try {
+ url = new URL(fileName);
+ return url.openStream();
+ } catch (final MalformedURLException e) {
+ throw new RuntimeException(e);
+ } catch (final IOException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ try {
+ return new FileInputStream(fileName);
+ } catch (final FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/FixedSizeQueue.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/FixedSizeQueue.java
new file mode 100644
index 0000000..c0c1878
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/FixedSizeQueue.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * 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.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Instance of this class are queues that have a fixed size.<br/>
+ * When the queue is full, the elements are shifted and the first element is
+ * lost.
+ *
+ * @param <T> Type of objects stored in this queue
+ */
+public class FixedSizeQueue<T> {
+
+ /** The buffer. */
+ private T[] buffer;
+
+ /** The index. */
+ private int index;
+
+ /**
+ * Constructor.
+ *
+ * @param capacity initial capacity
+ */
+ @SuppressWarnings("unchecked")
+ public FixedSizeQueue(final int capacity) {
+ this.buffer = (T[]) new Object[capacity];
+ this.index = 0;
+ }
+
+ /**
+ * Store an element in the buffer.
+ *
+ * @param element element to store
+ */
+ public void put(final T element) {
+ if (this.index == this.buffer.length) {
+ // Full
+ System.arraycopy(this.buffer, 1, this.buffer, 0, this.buffer.length - 1);
+ this.buffer[this.index - 1] = element;
+ } else {
+ this.buffer[this.index++] = element;
+ }
+ }
+
+ /**
+ * Gets the values.
+ *
+ * @return all values stored in this queue
+ */
+ public List<T> getValues() {
+ final List<T> list = new ArrayList<T>(this.index);
+ for (int i = 0; i < this.index; i++) {
+ if (this.buffer[i] != null) {
+ list.add(this.buffer[i]);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Gets the size.
+ *
+ * @return size of the buffer
+ */
+ public int getSize() {
+ return this.index;
+ }
+
+ /**
+ * Resize to.
+ *
+ * @param newSize new size of the buffer. If newSize is lower than the
+ * actual size, the buffer will contain the last elements that
+ * have been stored
+ */
+ @SuppressWarnings("unchecked")
+ public void resizeTo(int newSize) {
+ if (newSize < 0) {
+ newSize = 1;
+ }
+ if (newSize == this.buffer.length) {
+ return;
+ }
+ final T[] resizedBuffer = (T[]) new Object[newSize];
+ if (newSize > this.buffer.length) {
+ System.arraycopy(this.buffer, 0, resizedBuffer, 0, this.buffer.length);
+ } else {
+ final int startPos = Math.max(0, this.index - newSize);
+ System.arraycopy(this.buffer, startPos, resizedBuffer, 0, newSize);
+ this.index = newSize;
+ }
+ this.buffer = resizedBuffer;
+ }
+
+ /**
+ * Test method.
+ *
+ * @param args the arguments
+ */
+ public static void main(final String[] args) {
+ final FixedSizeQueue<Integer> buffer = new FixedSizeQueue<Integer>(5);
+ System.out.println("Filling...");
+ for (int i = 0; i < 10; i++) {
+ buffer.put(i);
+ System.out.println("i=" + i + ", size=" + buffer.getSize() + ", values=" + buffer.getValues());
+ }
+ System.out.println("Resize to 10...");
+ buffer.resizeTo(10);
+ System.out.println("size=" + buffer.getSize() + ", values=" + buffer.getValues());
+ buffer.put(10);
+ System.out.println("size=" + buffer.getSize() + ", values=" + buffer.getValues());
+
+ System.out.println("Resize to 3...");
+ buffer.resizeTo(3);
+ System.out.println("size=" + buffer.getSize() + ", values=" + buffer.getValues());
+ buffer.put(11);
+ System.out.println("size=" + buffer.getSize() + ", values=" + buffer.getValues());
+
+ System.out.println("Resize to 5...");
+ buffer.resizeTo(5);
+ buffer.put(12);
+ buffer.put(13);
+ buffer.put(14);
+ System.out.println("size=" + buffer.getSize() + ", values=" + buffer.getValues());
+ System.out.println("Resize to 3...");
+ buffer.resizeTo(3);
+ System.out.println("size=" + buffer.getSize() + ", values=" + buffer.getValues());
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/HTMLStyledTextParser.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/HTMLStyledTextParser.java
new file mode 100644
index 0000000..9a87ce7
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/HTMLStyledTextParser.java
@@ -0,0 +1,514 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 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.utils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+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.custom.StyleRange;
+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.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+/**
+ * Instances of this class are used to convert pseudo-HTML content of a styled
+ * text into style ranges.
+ */
+public class HTMLStyledTextParser {
+
+ /** The styled text. */
+ private final StyledText styledText;
+
+ /** The output. */
+ private StringBuilder output;
+
+ /** The current tag. */
+ private StringBuilder currentTag;
+
+ /** The list of styles. */
+ private final List<StyleRange> listOfStyles;
+
+ /** The stack. */
+ private final LinkedList<StyleRange> stack;
+
+ /** The current position. */
+ private int currentPosition;
+
+ /** The default height. */
+ private final int defaultHeight;
+
+ /** The Constant HTML_CODES. */
+ private static final Map<String, Integer[]> HTML_CODES = initHTMLCode();
+
+ /**
+ * Constructor.
+ *
+ * @param styledText styled text to analyze
+ */
+ HTMLStyledTextParser(final StyledText styledText) {
+ this.styledText = styledText;
+ listOfStyles = new ArrayList<StyleRange>();
+ stack = new LinkedList<StyleRange>();
+ final FontData data = styledText.getFont().getFontData()[0];
+ defaultHeight = data.getHeight();
+ }
+
+ /**
+ * Inits the html code.
+ *
+ * @return the map
+ */
+ private static Map<String, Integer[]> initHTMLCode() {
+ final Map<String, Integer[]> map = new HashMap<String, Integer[]>();
+
+ map.put("aliceblue", new Integer[] { 240, 248, 255 });
+ map.put("antiquewhite", new Integer[] { 250, 235, 215 });
+ map.put("aqua", new Integer[] { 0, 255, 255 });
+ map.put("aquamarine", new Integer[] { 127, 255, 212 });
+ map.put("azure", new Integer[] { 240, 255, 255 });
+ map.put("beige", new Integer[] { 245, 245, 220 });
+ map.put("bisque", new Integer[] { 255, 228, 196 });
+ map.put("black", new Integer[] { 0, 0, 0 });
+ map.put("blanchedalmond", new Integer[] { 255, 235, 205 });
+ map.put("blue", new Integer[] { 0, 0, 255 });
+ map.put("blueviolet", new Integer[] { 138, 43, 226 });
+ map.put("brown", new Integer[] { 165, 42, 42 });
+ map.put("burlywood", new Integer[] { 222, 184, 135 });
+ map.put("cadetblue", new Integer[] { 95, 158, 160 });
+ map.put("chartreuse", new Integer[] { 127, 255, 0 });
+ map.put("chocolate", new Integer[] { 210, 105, 30 });
+ map.put("coral", new Integer[] { 255, 127, 80 });
+ map.put("cornflowerblue", new Integer[] { 100, 149, 237 });
+ map.put("cornsilk", new Integer[] { 255, 248, 220 });
+ map.put("crimson", new Integer[] { 220, 20, 60 });
+ map.put("cyan", new Integer[] { 0, 255, 255 });
+ map.put("darkblue", new Integer[] { 0, 0, 139 });
+ map.put("darkcyan", new Integer[] { 0, 139, 139 });
+ map.put("darkgoldenrod", new Integer[] { 184, 134, 11 });
+ map.put("darkgray", new Integer[] { 169, 169, 169 });
+ map.put("darkgreen", new Integer[] { 0, 100, 0 });
+ map.put("darkgrey", new Integer[] { 169, 169, 169 });
+ map.put("darkkhaki", new Integer[] { 189, 183, 107 });
+ map.put("darkmagenta", new Integer[] { 139, 0, 139 });
+ map.put("darkolivegreen", new Integer[] { 85, 107, 47 });
+ map.put("darkorange", new Integer[] { 255, 140, 0 });
+ map.put("darkorchid", new Integer[] { 153, 50, 204 });
+ map.put("darkred", new Integer[] { 139, 0, 0 });
+ map.put("darksalmon", new Integer[] { 233, 150, 122 });
+ map.put("darkseagreen", new Integer[] { 143, 188, 143 });
+ map.put("darkslateblue", new Integer[] { 72, 61, 139 });
+ map.put("darkslategray", new Integer[] { 47, 79, 79 });
+ map.put("darkslategrey", new Integer[] { 47, 79, 79 });
+ map.put("darkturquoise", new Integer[] { 0, 206, 209 });
+ map.put("darkviolet", new Integer[] { 148, 0, 211 });
+ map.put("deeppink", new Integer[] { 255, 20, 147 });
+ map.put("deepskyblue", new Integer[] { 0, 191, 255 });
+ map.put("dimgray", new Integer[] { 105, 105, 105 });
+ map.put("dimgrey", new Integer[] { 105, 105, 105 });
+ map.put("dodgerblue", new Integer[] { 30, 144, 255 });
+ map.put("firebrick", new Integer[] { 178, 34, 34 });
+ map.put("floralwhite", new Integer[] { 255, 250, 240 });
+ map.put("forestgreen", new Integer[] { 34, 139, 34 });
+ map.put("fuchsia", new Integer[] { 255, 0, 255 });
+ map.put("gainsboro", new Integer[] { 220, 220, 220 });
+ map.put("ghostwhite", new Integer[] { 248, 248, 255 });
+ map.put("gold", new Integer[] { 255, 215, 0 });
+ map.put("goldenrod", new Integer[] { 218, 165, 32 });
+ map.put("gray", new Integer[] { 128, 128, 128 });
+ map.put("green", new Integer[] { 0, 128, 0 });
+ map.put("greenyellow", new Integer[] { 173, 255, 47 });
+ map.put("grey", new Integer[] { 128, 128, 128 });
+ map.put("honeydew", new Integer[] { 240, 255, 240 });
+ map.put("hotpink", new Integer[] { 255, 105, 180 });
+ map.put("indianred", new Integer[] { 205, 92, 92 });
+ map.put("indigo", new Integer[] { 75, 0, 130 });
+ map.put("ivory", new Integer[] { 255, 255, 240 });
+ map.put("khaki", new Integer[] { 240, 230, 140 });
+ map.put("lavender", new Integer[] { 230, 230, 250 });
+ map.put("lavenderblush", new Integer[] { 255, 240, 245 });
+ map.put("lawngreen", new Integer[] { 124, 252, 0 });
+ map.put("lemonchiffon", new Integer[] { 255, 250, 205 });
+ map.put("lightblue", new Integer[] { 173, 216, 230 });
+ map.put("lightcoral", new Integer[] { 240, 128, 128 });
+ map.put("lightcyan", new Integer[] { 224, 255, 255 });
+ map.put("lightgoldenrodyellow", new Integer[] { 250, 250, 210 });
+ map.put("lightgray", new Integer[] { 211, 211, 211 });
+ map.put("lightgreen", new Integer[] { 144, 238, 144 });
+ map.put("lightgrey", new Integer[] { 211, 211, 211 });
+ map.put("lightpink", new Integer[] { 255, 182, 193 });
+ map.put("lightsalmon", new Integer[] { 255, 160, 122 });
+ map.put("lightseagreen", new Integer[] { 32, 178, 170 });
+ map.put("lightskyblue", new Integer[] { 135, 206, 250 });
+ map.put("lightslategray", new Integer[] { 119, 136, 153 });
+ map.put("lightslategrey", new Integer[] { 119, 136, 153 });
+ map.put("lightsteelblue", new Integer[] { 176, 196, 222 });
+ map.put("lightyellow", new Integer[] { 255, 255, 224 });
+ map.put("lime", new Integer[] { 0, 255, 0 });
+ map.put("limegreen", new Integer[] { 50, 205, 50 });
+ map.put("linen", new Integer[] { 250, 240, 230 });
+ map.put("magenta", new Integer[] { 255, 0, 255 });
+ map.put("maroon", new Integer[] { 128, 0, 0 });
+ map.put("mediumaquamarine", new Integer[] { 102, 205, 170 });
+ map.put("mediumblue", new Integer[] { 0, 0, 205 });
+ map.put("mediumorchid", new Integer[] { 186, 85, 211 });
+ map.put("mediumpurple", new Integer[] { 147, 112, 219 });
+ map.put("mediumseagreen", new Integer[] { 60, 179, 113 });
+ map.put("mediumslateblue", new Integer[] { 123, 104, 238 });
+ map.put("mediumspringgreen", new Integer[] { 0, 250, 154 });
+ map.put("mediumturquoise", new Integer[] { 72, 209, 204 });
+ map.put("mediumvioletred", new Integer[] { 199, 21, 133 });
+ map.put("midnightblue", new Integer[] { 25, 25, 112 });
+ map.put("mintcream", new Integer[] { 245, 255, 250 });
+ map.put("mistyrose", new Integer[] { 255, 228, 225 });
+ map.put("moccasin", new Integer[] { 255, 228, 181 });
+ map.put("navajowhite", new Integer[] { 255, 222, 173 });
+ map.put("navy", new Integer[] { 0, 0, 128 });
+ map.put("oldlace", new Integer[] { 253, 245, 230 });
+ map.put("olive", new Integer[] { 128, 128, 0 });
+ map.put("olivedrab", new Integer[] { 107, 142, 35 });
+ map.put("orange", new Integer[] { 255, 165, 0 });
+ map.put("orangered", new Integer[] { 255, 69, 0 });
+ map.put("orchid", new Integer[] { 218, 112, 214 });
+ map.put("palegoldenrod", new Integer[] { 238, 232, 170 });
+ map.put("palegreen", new Integer[] { 152, 251, 152 });
+ map.put("paleturquoise", new Integer[] { 175, 238, 238 });
+ map.put("palevioletred", new Integer[] { 219, 112, 147 });
+ map.put("papayawhip", new Integer[] { 255, 239, 213 });
+ map.put("peachpuff", new Integer[] { 255, 218, 185 });
+ map.put("peru", new Integer[] { 205, 133, 63 });
+ map.put("pink", new Integer[] { 255, 192, 203 });
+ map.put("plum", new Integer[] { 221, 160, 221 });
+ map.put("powderblue", new Integer[] { 176, 224, 230 });
+ map.put("purple", new Integer[] { 128, 0, 128 });
+ map.put("red", new Integer[] { 255, 0, 0 });
+ map.put("rosybrown", new Integer[] { 188, 143, 143 });
+ map.put("royalblue", new Integer[] { 65, 105, 225 });
+ map.put("saddlebrown", new Integer[] { 139, 69, 19 });
+ map.put("salmon", new Integer[] { 250, 128, 114 });
+ map.put("sandybrown", new Integer[] { 244, 164, 96 });
+ map.put("seagreen", new Integer[] { 46, 139, 87 });
+ map.put("seashell", new Integer[] { 255, 245, 238 });
+ map.put("sienna", new Integer[] { 160, 82, 45 });
+ map.put("silver", new Integer[] { 192, 192, 192 });
+ map.put("skyblue", new Integer[] { 135, 206, 235 });
+ map.put("slateblue", new Integer[] { 106, 90, 205 });
+ map.put("slategray", new Integer[] { 112, 128, 144 });
+ map.put("slategrey", new Integer[] { 112, 128, 144 });
+ map.put("snow", new Integer[] { 255, 250, 250 });
+ map.put("springgreen", new Integer[] { 0, 255, 127 });
+ map.put("steelblue", new Integer[] { 70, 130, 180 });
+ map.put("tan", new Integer[] { 210, 180, 140 });
+ map.put("teal", new Integer[] { 0, 128, 128 });
+ map.put("thistle", new Integer[] { 216, 191, 216 });
+ map.put("tomato", new Integer[] { 255, 99, 71 });
+ map.put("turquoise", new Integer[] { 64, 224, 208 });
+ map.put("violet", new Integer[] { 238, 130, 238 });
+ map.put("wheat", new Integer[] { 245, 222, 179 });
+ map.put("white", new Integer[] { 255, 255, 255 });
+ map.put("whitesmoke", new Integer[] { 245, 245, 245 });
+ map.put("yellow", new Integer[] { 255, 255, 0 });
+ map.put("yellowgreen", new Integer[] { 154, 205, 50 });
+
+ return map;
+ }
+
+ /**
+ * Parse the content, build the list of style ranges and apply them to the
+ * styled text widget.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void parse() throws IOException {
+ if (styledText == null || "".equals(styledText.getText().trim())) {
+ return;
+ }
+
+ initBeforeParsing();
+
+ final String text = styledText.getText().trim();
+ final int max = text.length();
+ boolean inTag = false;
+
+ for (int i = 0; i < max; i++) {
+ final char currentChar = text.charAt(i);
+ if (currentChar == '<') {
+ inTag = true;
+ continue;
+ } else if (currentChar == '>') {
+ inTag = false;
+ handleTag();
+ currentTag.delete(0, currentTag.length());
+ } else {
+ if (inTag) {
+ currentTag.append(currentChar);
+ } else {
+ currentPosition++;
+ output.append(currentChar);
+ }
+ }
+ }
+ styledText.setText(output.toString());
+ styledText.setStyleRanges(listOfStyles.toArray(new StyleRange[listOfStyles.size()]));
+ }
+
+ /**
+ * Inits the before parsing.
+ */
+ private void initBeforeParsing() {
+ output = new StringBuilder();
+ currentTag = new StringBuilder();
+ listOfStyles.clear();
+ stack.clear();
+ currentPosition = 0;
+ }
+
+ /**
+ * Handle tag.
+ */
+ private void handleTag() {
+ final String tag = currentTag.toString().toLowerCase();
+ if ("br".equals(tag) || "br/".equals(tag)) {
+ output.append("\n");
+ currentPosition++;
+ return;
+ }
+
+ if ("b".equals(tag)) {
+ processBeginBold();
+ return;
+ }
+ if ("i".equals(tag)) {
+ processBeginItalic();
+ return;
+ }
+ if ("u".equals(tag)) {
+ processBeginUnderline();
+ return;
+ }
+ if (tag.startsWith("size=")) {
+ processBeginSize();
+ return;
+ }
+ if (tag.startsWith("color=")) {
+ processBeginColor();
+ return;
+ }
+ if (tag.startsWith("backgroundcolor=")) {
+ processBeginBackgroundColor();
+ return;
+ }
+
+ final String[] acceptedClosingTags = new String[] { "/b", "/i", "/u", "/size", "/color", "/backgroundcolor" };
+ for (final String closingTag : acceptedClosingTags) {
+ if (closingTag.equals(tag)) {
+ processEndTag(closingTag);
+ return;
+ }
+ }
+
+ final String text = "<" + tag + ">";
+ output.append(text);
+ currentPosition += text.length();
+
+ }
+
+ /**
+ * Process begin bold.
+ */
+ private void processBeginBold() {
+ final StyleRange currentStyleRange = new StyleRange();
+ currentStyleRange.start = currentPosition;
+ currentStyleRange.length = 0;
+ currentStyleRange.fontStyle = SWT.BOLD;
+ currentStyleRange.data = "</b>";
+ stack.push(currentStyleRange);
+ }
+
+ /**
+ * Process end tag.
+ *
+ * @param expectedTag the expected tag
+ */
+ private void processEndTag(final String expectedTag) {
+ final StyleRange currentStyleRange = stack.pop();
+ final String wholeExpectedTag = "<" + expectedTag + ">";
+ if (!wholeExpectedTag.equals(currentStyleRange.data)) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Error at position #").append(currentPosition).append(" - closing ").append(wholeExpectedTag).append(" tag found but ");
+ sb.append(currentStyleRange.data).append(" tag expected !");
+ throw new RuntimeException(sb.toString());
+ }
+ currentStyleRange.length = currentPosition - currentStyleRange.start;
+ listOfStyles.add(currentStyleRange);
+
+ }
+
+ /**
+ * Process begin italic.
+ */
+ private void processBeginItalic() {
+ final StyleRange currentStyleRange = new StyleRange();
+ currentStyleRange.start = currentPosition;
+ currentStyleRange.length = 0;
+ currentStyleRange.fontStyle = SWT.ITALIC;
+ currentStyleRange.data = "</i>";
+ stack.push(currentStyleRange);
+ }
+
+ /**
+ * Process begin underline.
+ */
+ private void processBeginUnderline() {
+ final StyleRange currentStyleRange = new StyleRange();
+ currentStyleRange.start = currentPosition;
+ currentStyleRange.length = 0;
+ currentStyleRange.fontStyle = SWT.NONE;
+ currentStyleRange.underline = true;
+ currentStyleRange.data = "</u>";
+ stack.push(currentStyleRange);
+ }
+
+ /**
+ * Process begin size.
+ */
+ private void processBeginSize() {
+ final StyleRange currentStyleRange = new StyleRange();
+ currentStyleRange.start = currentPosition;
+ currentStyleRange.length = 0;
+ currentStyleRange.fontStyle = SWT.NONE;
+ currentStyleRange.font = computeFont();
+ currentStyleRange.data = "</size>";
+ stack.push(currentStyleRange);
+ }
+
+ /**
+ * Compute font.
+ *
+ * @return the font
+ */
+ private Font computeFont() {
+ final String fontSize = currentTag.toString().toLowerCase().replace("size=", "");
+ if (fontSize.length() == 0) {
+ throw new RuntimeException("Argument size is empty !");
+ }
+ int newSize = defaultHeight;
+ if (fontSize.startsWith("+")) {
+ final int delta = Integer.valueOf(fontSize.substring(1));
+ newSize += delta;
+ } else if (fontSize.startsWith("-")) {
+ final int delta = Integer.valueOf(fontSize.substring(1));
+ newSize -= delta;
+ }
+
+ final FontData fd = styledText.getFont().getFontData()[0];
+ final Font newFont = new Font(styledText.getDisplay(), fd.getName(), newSize, SWT.NONE);
+ styledText.addListener(SWT.Dispose, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ newFont.dispose();
+ }
+ });
+ return newFont;
+ }
+
+ /**
+ * Process begin color.
+ */
+ private void processBeginColor() {
+ final StyleRange currentStyleRange = new StyleRange();
+ currentStyleRange.start = currentPosition;
+ currentStyleRange.length = 0;
+ currentStyleRange.fontStyle = SWT.NONE;
+ currentStyleRange.foreground = computeColor();
+ currentStyleRange.data = "</color>";
+ stack.push(currentStyleRange);
+ }
+
+ /**
+ * Compute color.
+ *
+ * @return the color
+ */
+ private Color computeColor() {
+ final String fontColor = currentTag.toString().toLowerCase().replace("color=", "").replace("background", "");
+ if (fontColor.length() == 0) {
+ throw new RuntimeException("Argument color is empty !");
+ }
+
+ int red, green, blue;
+ if (fontColor.startsWith("#")) {
+ final String hexa = fontColor.substring(1);
+ if (hexa.length() != 6) {
+ throw new RuntimeException("Argument [" + hexa + "] is not valid !");
+ }
+ try {
+ red = Integer.parseInt(hexa.substring(0, 2).toLowerCase(), 16);
+ green = Integer.parseInt(hexa.substring(2, 4).toLowerCase(), 16);
+ blue = Integer.parseInt(hexa.substring(4, 6).toLowerCase(), 16);
+ } catch (final NumberFormatException nfe) {
+ throw new RuntimeException("Argument [" + hexa + "] is not valid !");
+ }
+ } else if (fontColor.indexOf(',') > -1) {
+ final String[] args = fontColor.split(",");
+ if (args.length != 3) {
+ throw new RuntimeException("Argument [" + fontColor + "] is not valid !");
+ }
+ try {
+ red = Integer.parseInt(args[0]);
+ green = Integer.parseInt(args[1]);
+ blue = Integer.parseInt(args[2]);
+ } catch (final NumberFormatException nfe) {
+ throw new RuntimeException("Argument [" + fontColor + "] is not valid !");
+ }
+ } else {
+ final Integer[] rgb = HTML_CODES.get(fontColor.toLowerCase());
+ if (rgb == null) {
+ red = 0;
+ green = 0;
+ blue = 0;
+ } else {
+ red = rgb[0];
+ green = rgb[1];
+ blue = rgb[2];
+ }
+ }
+ final Color color = new Color(styledText.getDisplay(), red, green, blue);
+ styledText.addListener(SWT.Dispose, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ color.dispose();
+ }
+ });
+ return color;
+ }
+
+ /**
+ * Process begin background color.
+ */
+ private void processBeginBackgroundColor() {
+ final StyleRange currentStyleRange = new StyleRange();
+ currentStyleRange.start = currentPosition;
+ currentStyleRange.length = 0;
+ currentStyleRange.fontStyle = SWT.NONE;
+ currentStyleRange.background = computeColor();
+ currentStyleRange.data = "</backgroundcolor>";
+ stack.push(currentStyleRange);
+ }
+
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/ReadOnlyStyledText.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/ReadOnlyStyledText.java
new file mode 100644
index 0000000..10fda7e
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/ReadOnlyStyledText.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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 implementation and API
+ *******************************************************************************/
+package org.mihalis.opal.utils;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseTrackAdapter;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Instances of this class are StyledText that are read-only, that means that we
+ * use it only as a renderer.
+ *
+ * @see StyledText
+ */
+public class ReadOnlyStyledText extends StyledText {
+
+ /**
+ * 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 SWT#FULL_SELECTION
+ * @see SWT#MULTI
+ * @see SWT#SINGLE
+ * @see #getStyle
+ * @see StyledText
+ * @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 ReadOnlyStyledText(final Composite parent, final int style) {
+ super(parent, style | SWT.WRAP | SWT.READ_ONLY);
+ addMouseTrackListener(new MouseTrackAdapter() {
+ @Override
+ public void mouseEnter(final MouseEvent e) {
+ setCursor(getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
+ }
+ });
+ setCaret(null);
+ addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ setSelection(0, 0);
+ }
+
+ });
+ }
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/ResourceManager.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/ResourceManager.java
new file mode 100644
index 0000000..9abcc71
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/ResourceManager.java
@@ -0,0 +1,188 @@
+package org.mihalis.opal.utils;
+
+import java.util.ResourceBundle;
+
+/**
+ * The Class ResourceManager.
+ */
+public class ResourceManager {
+
+ /** The Constant RSC. */
+ private static final ResourceBundle RSC = ResourceBundle.getBundle("resources/opal");
+
+ /** The Constant OK. */
+ public static final String OK = "Ok";
+
+ /** The Constant CANCEL. */
+ public static final String CANCEL = "Cancel";
+
+ /** The Constant CLOSE. */
+ public static final String CLOSE = "Close";
+
+ /** The Constant YES. */
+ public static final String YES = "Yes";
+
+ /** The Constant NO. */
+ public static final String NO = "No";
+
+ /** The Constant MEGABYTES. */
+ public static final String MEGABYTES = "megabytes";
+
+ /** The Constant PERFORM_GC. */
+ public static final String PERFORM_GC = "performGC";
+
+ /** The Constant LOGIN. */
+ public static final String LOGIN = "login";
+
+ /** The Constant NAME. */
+ public static final String NAME = "name";
+
+ /** The Constant PASSWORD. */
+ public static final String PASSWORD = "password"; // NOSONAR
+
+ /** The Constant REMEMBER_PASSWORD. */
+ public static final String REMEMBER_PASSWORD = "rememberPassword"; // NOSONAR
+
+ /** The Constant LOGIN_FAILED. */
+ public static final String LOGIN_FAILED = "loginFailed";
+
+ /** The Constant INPUT. */
+ public static final String INPUT = "Input";
+
+ /** The Constant APPLICATION_ERROR. */
+ public static final String APPLICATION_ERROR = "ApplicationError";
+
+ /** The Constant INFORMATION. */
+ public static final String INFORMATION = "Information";
+
+ /** The Constant WARNING. */
+ public static final String WARNING = "Warning";
+
+ /** The Constant CHOICE. */
+ public static final String CHOICE = "Choice";
+
+ /** The Constant EXCEPTION. */
+ public static final String EXCEPTION = "Exception";
+
+ /** The Constant SELECT. */
+ public static final String SELECT = "Select";
+
+ /** The Constant FEWER_DETAILS. */
+ public static final String FEWER_DETAILS = "FewerDetails";
+
+ /** The Constant MORE_DETAILS. */
+ public static final String MORE_DETAILS = "MoreDetails";
+
+ /** The Constant TIP_OF_THE_DAY. */
+ public static final String TIP_OF_THE_DAY = "tipOfTheDay";
+
+ /** The Constant DID_YOU_KNOW. */
+ public static final String DID_YOU_KNOW = "didYouKnow";
+
+ /** The Constant SHOW_TIP_AT_STARTUP. */
+ public static final String SHOW_TIP_AT_STARTUP = "showTipAtStartup";
+
+ /** The Constant PREVIOUS_TIP. */
+ public static final String PREVIOUS_TIP = "previousTip";
+
+ /** The Constant NEXT_TIP. */
+ public static final String NEXT_TIP = "nextTip";
+
+ /** The Constant CHOOSE. */
+ public static final String CHOOSE = "choose";
+
+ /** The Constant PREFERENCES. */
+ public static final String PREFERENCES = "preferences";
+
+ /** The Constant VALID_URL. */
+ public static final String VALID_URL = "validURL";
+
+ /** The Constant CHOOSE_DIRECTORY. */
+ public static final String CHOOSE_DIRECTORY = "chooseDirectory";
+
+ /** The Constant ITALIC. */
+ public static final String ITALIC = "italic";
+
+ /** The Constant BOLD. */
+ public static final String BOLD = "bold";
+
+ /** The Constant CATEGORY_SHORT_DESCRIPTION. */
+ public static final String CATEGORY_SHORT_DESCRIPTION = "category.shortDescription";
+
+ /** The Constant DESCRIPTION_SHORT_DESCRIPTION. */
+ public static final String DESCRIPTION_SHORT_DESCRIPTION = "description.shortDescription";
+
+ /** The Constant SORT_SHORT_DESCRIPTION. */
+ public static final String SORT_SHORT_DESCRIPTION = "sort.shortDescription";
+
+ /** The Constant PROPERTY. */
+ public static final String PROPERTY = "property";
+
+ /** The Constant VALUE. */
+ public static final String VALUE = "value";
+
+ /** The Constant EDIT_PROPERTY. */
+ public static final String EDIT_PROPERTY = "editProperty";
+
+ /** The Constant WIDTH. */
+ public static final String WIDTH = "width";
+
+ /** The Constant HEIGHT. */
+ public static final String HEIGHT = "height";
+
+ /** The Constant TOP. */
+ public static final String TOP = "top";
+
+ /** The Constant BOTTOM. */
+ public static final String BOTTOM = "bottom";
+
+ /** The Constant LEFT. */
+ public static final String LEFT = "left";
+
+ /** The Constant RIGHT. */
+ public static final String RIGHT = "right";
+
+ /** The Constant ERASE_PROPERTY. */
+ public static final String ERASE_PROPERTY = "eraseProperty";
+
+ /** The Constant PHYSICAL_MEMORY. */
+ public static final String PHYSICAL_MEMORY = "physicalMemory";
+
+ /** The Constant HEAP_MEMORY. */
+ public static final String HEAP_MEMORY = "heapMemory";
+
+ /** The Constant THREADS. */
+ public static final String THREADS = "threads";
+
+ /** The Constant CPU_USAGE. */
+ public static final String CPU_USAGE = "cpuUsage";
+
+ /** The Constant PEAK. */
+ public static final String PEAK = "peak";
+
+ /** The Constant MB. */
+ public static final String MB = "mb";
+
+ /** The Constant CALCULATOR_DIVIDE_BY_ZERO. */
+ public static final String CALCULATOR_DIVIDE_BY_ZERO = "calculator.dividebyzero";
+
+ /** The Constant CALCULATOR_INVALID_VALUE. */
+ public static final String CALCULATOR_INVALID_VALUE = "calculator.invalid";
+
+ /** The Constant MULTICHOICE_MESSAGE. */
+ public static final String MULTICHOICE_MESSAGE = "multichoice.message";
+
+ /** The Constant MULTICHOICE_MESSAGE_PLURAL. */
+ public static final String MULTICHOICE_MESSAGE_PLURAL = "multichoice.message.plural";
+
+ /**
+ * Get a translated label.
+ *
+ * @param key key to get
+ * @return the translated value of the key
+ */
+ public static String getLabel(final String key) {
+ return RSC.getString(key);
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/SWTGraphicUtil.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/SWTGraphicUtil.java
new file mode 100644
index 0000000..6557ef7
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/SWTGraphicUtil.java
@@ -0,0 +1,573 @@
+/*******************************************************************************
+ * 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.utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+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.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.Resource;
+import org.eclipse.swt.graphics.Transform;
+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.Listener;
+import org.eclipse.swt.widgets.Monitor;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * This class is a singleton that provides useful methods.
+ */
+public class SWTGraphicUtil {
+
+ /**
+ * Constructor.
+ */
+ private SWTGraphicUtil() {
+ }
+
+ /**
+ * Dispose safely any SWT resource when a widget is disposed.
+ *
+ * @param widget widget attached to the resource
+ * @param resource the resource to dispose
+ */
+ public static void addDisposer(final Widget widget, final Resource resource) {
+ widget.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ safeDispose(resource);
+ }
+ });
+ }
+
+ /**
+ * Dispose safely any SWT resource.
+ *
+ * @param resource the resource to dispose
+ */
+ public static void safeDispose(final Resource resource) {
+ if (resource != null && !resource.isDisposed()) {
+ resource.dispose();
+ }
+ }
+
+ /**
+ * Create a color that is disposed automatically.
+ *
+ * @param r red component
+ * @param g green component
+ * @param b blue component
+ * @return the color
+ */
+ public static Color getColorSafely(final int r, final int g, final int b) {
+ final Display display = Display.getCurrent();
+ final Color color = new Color(display, r, g, b);
+ display.addListener(SWT.Dispose, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ if (!color.isDisposed()) {
+ color.dispose();
+ }
+ }
+ });
+ return color;
+ }
+
+ /**
+ * Loads an image and create a SWT Image corresponding to this file.
+ *
+ * @param fileName file name of the image
+ * @return an image
+ * @see org.eclipse.swt.graphics.Image
+ */
+ public static Image createImageFromFile(final String fileName) {
+ if (new File(fileName).exists()) {
+ return new Image(Display.getCurrent(), fileName);
+ } else {
+ return new Image(Display.getCurrent(), SWTGraphicUtil.class.getClassLoader().getResourceAsStream(fileName));
+ }
+ }
+
+ /**
+ * Create a reflected image of a source Inspired by Daniel Spiewak work
+ * (http://www.eclipsezone.com/eclipse/forums/t91013.html)
+ *
+ * @param source source to be reflected
+ * @return the source image with a reflection
+ */
+ public static Image createReflectedImage(final Image source) {
+ if (source == null) {
+ return null;
+ }
+
+ if (source.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ // Create a new image
+ final Rectangle sourceBounds = source.getBounds();
+ final Image newImage = new Image(source.getDevice(), new Rectangle(0, 0, sourceBounds.width, (int) (sourceBounds.height * 1.5)));
+ final GC gc = new GC(newImage);
+ gc.setAdvanced(true);
+
+ gc.drawImage(source, 0, 0);
+
+ // Add the reflection
+ final Transform t = new Transform(source.getDevice());
+ t.setElements(1, 0, 0, -.5f, 0, sourceBounds.height + sourceBounds.height / 2);
+ gc.setTransform(t);
+
+ gc.drawImage(source, 0, 0);
+
+ t.dispose();
+ gc.dispose();
+
+ // And add the alpha mask
+ final ImageData imgData = newImage.getImageData();
+ final int width = imgData.width;
+ final int height = imgData.height;
+ final byte[] alphaData = new byte[height * width];
+
+ final byte[] noAlpha = new byte[width];
+ for (int x = 0; x < width; x++) {
+ noAlpha[x] = (byte) 255;
+ }
+
+ for (int y = 0; y < height; y++) {
+ final byte[] alphaRow = new byte[width];
+ if (y < sourceBounds.height) {
+ System.arraycopy(noAlpha, 0, alphaData, y * width, width);
+ } else {
+ for (int x = 0; x < width; x++) {
+ alphaRow[x] = (byte) (255 - 255 * y / height);
+ }
+ System.arraycopy(alphaRow, 0, alphaData, y * width, width);
+ }
+
+ }
+ imgData.alphaData = alphaData;
+ newImage.dispose();
+ return new Image(source.getDevice(), imgData);
+ }
+
+ /**
+ * Returns a new scaled image.
+ *
+ * @param source the image to be scaled
+ * @param newWidth new width of the image
+ * @param newHeight new height of the image
+ * @return a scaled image of the source
+ */
+ public static Image resize(final Image source, final int newWidth, final int newHeight) {
+ if (source == null) {
+ return null;
+ }
+
+ if (source.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ final Image scaledImage = new Image(source.getDevice(), newWidth, newHeight);
+ final GC gc = new GC(scaledImage);
+ gc.setAntialias(SWT.ON);
+ gc.setInterpolation(SWT.HIGH);
+ gc.drawImage(source, 0, 0, source.getBounds().width, source.getBounds().height, 0, 0, newWidth, newHeight);
+ gc.dispose();
+
+ return scaledImage;
+ }
+
+ /**
+ * Create a reflected and resized version of an image.
+ *
+ * @param source source image to be scaled and reflected
+ * @param newWidth new width of the scaled image
+ * @param newHeight new height of the scaled image
+ * @return the resized and reflected image
+ */
+ public static Image createReflectedResizedImage(final Image source, final int newWidth, final int newHeight) {
+ if (source == null) {
+ return null;
+ }
+
+ if (source.isDisposed()) {
+ SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ }
+
+ final Image newImage = new Image(source.getDevice(), newWidth, (int) (newHeight * 1.5));
+ final GC gc = new GC(newImage);
+ gc.setAntialias(SWT.ON);
+ gc.setInterpolation(SWT.HIGH);
+ gc.drawImage(source, 0, 0, source.getBounds().width, source.getBounds().height, 0, 0, newWidth, newHeight);
+
+ // Add the reflection
+ final Transform t = new Transform(source.getDevice());
+ t.setElements(1, 0, 0, -.5f, 0, (float) (newHeight * 1.5));
+ gc.setTransform(t);
+
+ gc.drawImage(source, 0, 0, source.getBounds().width, source.getBounds().height, 0, 0, newWidth, newHeight);
+
+ t.dispose();
+ gc.dispose();
+
+ // And add the alpha mask
+ final ImageData imgData = newImage.getImageData();
+ final int width = imgData.width;
+ final int height = imgData.height;
+ final byte[] alphaData = new byte[height * width];
+
+ final byte[] noAlpha = new byte[width];
+ for (int x = 0; x < width; x++) {
+ noAlpha[x] = (byte) 255;
+ }
+
+ for (int y = 0; y < height; y++) {
+ final byte[] alphaRow = new byte[width];
+ if (y < newHeight) {
+ System.arraycopy(noAlpha, 0, alphaData, y * width, width);
+ } else {
+ for (int x = 0; x < width; x++) {
+ alphaRow[x] = (byte) (255 - 255 * y / height);
+ }
+ System.arraycopy(alphaRow, 0, alphaData, y * width, width);
+ }
+
+ }
+ imgData.alphaData = alphaData;
+
+ newImage.dispose();
+
+ return new Image(source.getDevice(), imgData);
+
+ }
+
+ /**
+ * Center a shell on the primary monitor.
+ *
+ * @param shell shell to center
+ */
+ public static void centerShell(final Shell shell) {
+ final Monitor primary = shell.getDisplay().getPrimaryMonitor();
+ final Rectangle bounds = primary.getBounds();
+ final Rectangle rect = shell.getBounds();
+ final int x = bounds.x + (bounds.width - rect.width) / 2;
+ final int y = bounds.y + (bounds.height - rect.height) / 2;
+ shell.setLocation(x, y);
+ }
+
+ /**
+ * Gets the bounds of monitor on which shell is displayed.
+ *
+ * @param shell the shell
+ * @return the bounds of the monitor on which the shell is running
+ */
+ public static Rectangle getBoundsOfMonitorOnWhichShellIsDisplayed(final Shell shell) {
+ for (final Monitor monitor : shell.getDisplay().getMonitors()) {
+ final Rectangle monitorBounds = monitor.getBounds();
+ final Rectangle shellBounds = shell.getBounds();
+ if (monitorBounds.contains(shellBounds.x, shellBounds.y)) {
+ return monitorBounds;
+ }
+ }
+ final Monitor primary = shell.getDisplay().getPrimaryMonitor();
+ return primary.getBounds();
+ }
+
+ /**
+ * Apply a very basic pseudo-HTML formating to a text stored in a StyledText
+ * widget. Supported tags are <b>, <i>, <u> , <COLOR>, <backgroundcolor>,
+ * <size> and <BbrR/>
+ *
+ * @param styledText styled text that contains an HTML text
+ */
+ public static void applyHTMLFormating(final StyledText styledText) {
+ try {
+ new HTMLStyledTextParser(styledText).parse();
+ } catch (final IOException e) { // NOSONAR
+ e.printStackTrace(); // NOSONAR
+ }
+ }
+
+ /**
+ * Blur.
+ *
+ * @author Nicholas Rajendram
+ * @param originalImageData The ImageData to be average blurred.
+ * Transparency information will be ignored.
+ * @param radius the number of radius pixels to consider when blurring
+ * image.
+ * @return A blurred copy of the image data, or null if an error occurred.
+ * @see http://www.eclipse.org/articles/article.php?file=Article-
+ * SimpleImageEffectsForSWT/index.html
+ */
+ public static ImageData blur(final ImageData originalImageData, int radius) {
+
+ if (radius < 1) {
+ return originalImageData;
+ }
+
+ // prepare new image data with 24-bit direct palette to hold blurred
+ // copy of image
+ final ImageData newImageData = new ImageData(originalImageData.width, originalImageData.height, 24, new PaletteData(0xFF, 0xFF00, 0xFF0000));
+ if (radius >= newImageData.height || radius >= newImageData.width) {
+ radius = Math.min(newImageData.height, newImageData.width) - 1;
+ }
+ // initialize cache
+ final ArrayList<RGB[]> rowCache = new ArrayList<RGB[]>();
+ final int cacheSize = radius * 2 + 1 > newImageData.height ? newImageData.height : radius * 2 + 1; // number
+ // of
+ // rows
+ // of
+ // imageData
+ // we
+ // cache
+ int cacheStartIndex = 0; // which row of imageData the cache begins with
+ for (int row = 0; row < cacheSize; row++) {
+ // row data is horizontally blurred before caching
+ rowCache.add(rowCache.size(), blurRow(originalImageData, row, radius));
+ }
+
+ // sum red, green, and blue values separately for averaging
+ final RGB[] rowRGBSums = new RGB[newImageData.width];
+ final int[] rowRGBAverages = new int[newImageData.width];
+ int topSumBoundary = 0; // current top row of summed values scope
+ int targetRow = 0; // row with RGB averages to be determined
+ int bottomSumBoundary = 0; // current bottom row of summed values scope
+ int numRows = 0; // number of rows included in current summing scope
+ for (int i = 0; i < newImageData.width; i++) {
+ rowRGBSums[i] = new RGB(0, 0, 0);
+ }
+
+ while (targetRow < newImageData.height) {
+ if (bottomSumBoundary < newImageData.height) {
+ do {
+ // sum pixel RGB values for each column in our radius scope
+ for (int col = 0; col < newImageData.width; col++) {
+ rowRGBSums[col].red += rowCache.get(bottomSumBoundary - cacheStartIndex)[col].red;
+ rowRGBSums[col].green += rowCache.get(bottomSumBoundary - cacheStartIndex)[col].green;
+ rowRGBSums[col].blue += rowCache.get(bottomSumBoundary - cacheStartIndex)[col].blue;
+ }
+ numRows++;
+ bottomSumBoundary++; // move bottom scope boundary lower
+ if (bottomSumBoundary < newImageData.height && bottomSumBoundary - cacheStartIndex > radius * 2) {
+ // grow cache
+ rowCache.add(rowCache.size(), blurRow(originalImageData, bottomSumBoundary, radius));
+ }
+ } while (bottomSumBoundary <= radius); // to initialize
+ // rowRGBSums at start
+ }
+
+ if (targetRow - topSumBoundary > radius) {
+ // subtract values of top row from sums as scope of summed
+ // values moves down
+ for (int col = 0; col < newImageData.width; col++) {
+ rowRGBSums[col].red -= rowCache.get(topSumBoundary - cacheStartIndex)[col].red;
+ rowRGBSums[col].green -= rowCache.get(topSumBoundary - cacheStartIndex)[col].green;
+ rowRGBSums[col].blue -= rowCache.get(topSumBoundary - cacheStartIndex)[col].blue;
+ }
+ numRows--;
+ topSumBoundary++; // move top scope boundary lower
+ rowCache.remove(0); // remove top row which is out of summing
+ // scope
+ cacheStartIndex++;
+ }
+
+ // calculate each column's RGB-averaged pixel
+ for (int col = 0; col < newImageData.width; col++) {
+ rowRGBAverages[col] = newImageData.palette.getPixel(new RGB(rowRGBSums[col].red / numRows, rowRGBSums[col].green / numRows, rowRGBSums[col].blue / numRows));
+ }
+
+ // replace original pixels
+ newImageData.setPixels(0, targetRow, newImageData.width, rowRGBAverages, 0);
+ targetRow++;
+ }
+ return newImageData;
+ }
+
+ /**
+ * Average blurs a given row of image data. Returns the blurred row as a
+ * matrix of separated RGB values.
+ *
+ * @param originalImageData the original image data
+ * @param row the row
+ * @param radius the radius
+ * @return the RG b[]
+ */
+ private static RGB[] blurRow(final ImageData originalImageData, final int row, final int radius) {
+ final RGB[] rowRGBAverages = new RGB[originalImageData.width]; // resulting
+ // rgb
+ // averages
+ final int[] lineData = new int[originalImageData.width];
+ originalImageData.getPixels(0, row, originalImageData.width, lineData, 0);
+ int r = 0, g = 0, b = 0; // sum red, green, and blue values separately
+ // for averaging
+ int leftSumBoundary = 0; // beginning index of summed values scope
+ int targetColumn = 0; // column of RGB average to be determined
+ int rightSumBoundary = 0; // ending index of summed values scope
+ int numCols = 0; // number of columns included in current summing scope
+ RGB rgb;
+ while (targetColumn < lineData.length) {
+ if (rightSumBoundary < lineData.length) {
+ // sum RGB values for each pixel in our radius scope
+ do {
+ rgb = originalImageData.palette.getRGB(lineData[rightSumBoundary]);
+ r += rgb.red;
+ g += rgb.green;
+ b += rgb.blue;
+ numCols++;
+ rightSumBoundary++;
+ } while (rightSumBoundary <= radius); // to initialize summing
+ // scope at start
+ }
+
+ // subtract sum of left pixel as summing scope moves right
+ if (targetColumn - leftSumBoundary > radius) {
+ rgb = originalImageData.palette.getRGB(lineData[leftSumBoundary]);
+ r -= rgb.red;
+ g -= rgb.green;
+ b -= rgb.blue;
+ numCols--;
+ leftSumBoundary++;
+ }
+
+ // calculate RGB averages
+ rowRGBAverages[targetColumn] = new RGB(r / numCols, g / numCols, b / numCols);
+ targetColumn++;
+ }
+ return rowRGBAverages;
+ }
+
+ /**
+ * Enable all widgets of a control.
+ *
+ * @param control control to enable/disable
+ */
+ public static void enableAllChildrenWidgets(final Control control) {
+ if (control instanceof Composite) {
+ for (final Control c : ((Composite) control).getChildren()) {
+ enableAllChildrenWidgets(c);
+ }
+ }
+ boolean enable = true;
+ final Boolean previousState = (Boolean) control.getData(SWTGraphicUtil.class.toString() + "_enableState");
+ if (previousState != null) {
+ enable = previousState;
+ }
+ control.setEnabled(enable);
+ }
+
+ /**
+ * Disable all widgets of a control.
+ *
+ * @param control control to enable/disable
+ */
+ public static void disableAllChildrenWidgets(final Control control) {
+ if (control instanceof Composite) {
+ for (final Control c : ((Composite) control).getChildren()) {
+ disableAllChildrenWidgets(c);
+ }
+ }
+ control.setData(SWTGraphicUtil.class.toString() + "_enableState", control.isEnabled());
+ control.setEnabled(false);
+ }
+
+ /**
+ * Build a font from a given control. Useful if we just want a bold label
+ * for example
+ *
+ * @param control control that handle the default font
+ * @param style new style
+ * @return a font with the given style
+ */
+ public static Font buildFontFrom(final Control control, final int style) {
+ final Font temp = control.getFont();
+ final FontData[] fontData = temp.getFontData();
+ if (fontData == null || fontData.length == 0) {
+ return temp;
+ }
+ return new Font(control.getDisplay(), fontData[0].getName(), fontData[0].getHeight(), style);
+ }
+
+ /**
+ * Build a font from a given control. Useful if we just want a bold label
+ * for example
+ *
+ * @param control control that handle the default font
+ * @param style new style
+ * @param size the size
+ * @return a font with the given style
+ */
+ public static Font buildFontFrom(final Control control, final int style, final int size) {
+ final Font temp = control.getFont();
+ final FontData[] fontData = temp.getFontData();
+ if (fontData == null || fontData.length == 0) {
+ return temp;
+ }
+ return new Font(control.getDisplay(), fontData[0].getName(), size, style);
+ }
+
+ /**
+ * Checks if is mac os.
+ *
+ * @return <code>true</code> if the operating system is MacOS, false
+ * otherwise
+ */
+ public static boolean isMacOS() {
+ final String OS = System.getProperty("os.name").toLowerCase();
+ return OS.indexOf("mac") >= 0;
+ }
+
+ /**
+ * Gets the default color.
+ *
+ * @param control the control
+ * @param red the red
+ * @param green the green
+ * @param blue the blue
+ * @return a color that will be disposed when <code>control</code> is
+ * disposed
+ */
+ public static Color getDefaultColor(final Control control, final int red, final int green, final int blue) {
+ final Color defaultColor = new Color(control.getDisplay(), red, green, blue);
+ addDisposer(control, defaultColor);
+ return defaultColor;
+ }
+
+ /**
+ * Compute width.
+ *
+ * @param text the text
+ * @return the width of text
+ */
+ public static int computeWidth(final String text) {
+ final GC gc = new GC(Display.getDefault());
+ final int width = gc.textExtent(text).x;
+ gc.dispose();
+ return width;
+ }
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/SimpleSelectionAdapter.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/SimpleSelectionAdapter.java
new file mode 100644
index 0000000..66b8f85
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/SimpleSelectionAdapter.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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.utils;
+
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+
+/**
+ * This class is an adapter for the SelectionListener. Both behaviours (DefaultSelected and Selected) are doing the same thing
+ */
+public abstract class SimpleSelectionAdapter implements SelectionListener {
+
+ /** Widget default selected.
+ *
+ * @param e the e
+ * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ this.handle(e);
+
+ }
+
+ /** Widget selected.
+ *
+ * @param e the e
+ * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ this.handle(e);
+
+ }
+
+ /**
+ * Sent when selection occurs in the control.
+ *
+ * @param e - an event containing information about the selection
+ */
+ public abstract void handle(SelectionEvent e);
+
+}
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/StringUtil.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/StringUtil.java
new file mode 100644
index 0000000..88ebdad
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/utils/StringUtil.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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.utils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * This class provides useful String manipulation methods.
+ */
+public class StringUtil {
+
+ /**
+ * Returns a "safe" string representation. If source is null, return an
+ * empty string
+ *
+ * @param source source string
+ * @return the string representation of the source (without space) if the
+ * source is not <code>null</code>, or an empty string otherwise
+ */
+ public static String safeToString(final Object source) {
+ return source == null ? "" : source.toString().trim();
+ }
+
+ /**
+ * Check if a string is empty or null.
+ *
+ * @param source source string
+ * @return <code>true</code> is the string is empty or null,
+ * <code>false</code> otherwise
+ */
+ public static boolean isEmpty(final String source) {
+ return source == null || source.trim().isEmpty();
+ }
+
+ /**
+ * Converts exception stack trace as string.
+ *
+ * @param exception exception to convert
+ * @return a string that contains the exception
+ */
+ public static final String stackStraceAsString(final Throwable exception) {
+ final StringWriter stringWriter = new StringWriter();
+ exception.printStackTrace(new PrintWriter(stringWriter)); // NOSONAR
+ return stringWriter.toString();
+ }
+
+ /**
+ * Insert a string in a middle of another string.
+ *
+ * @param source source string
+ * @param newEntry string to insert into source
+ * @param position position to insert source
+ * @return the new string
+ */
+ public static String insertString(final String source, final String newEntry, final int position) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(source.substring(0, position)).append(newEntry).append(source.substring(position));
+ return sb.toString();
+ }
+
+ /**
+ * Remove a character in a String.
+ *
+ * @param source source string
+ * @param position position of the character to remove
+ * @return the string without the character
+ */
+ public static String removeCharAt(final String source, final int position) {
+ final StringBuilder sb = new StringBuilder();
+ if (position == source.length()) {
+ return source;
+ }
+ sb.append(source.substring(0, position)).append(source.substring(position + 1));
+ return sb.toString();
+ }
+}
diff --git a/org.mihalis.opal/src/main/resources/images/angleBackground.png b/org.mihalis.opal/src/main/resources/images/angleBackground.png
new file mode 100644
index 0000000..3f6d886
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/angleBackground.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/angleButtonFocus.png b/org.mihalis.opal/src/main/resources/images/angleButtonFocus.png
new file mode 100644
index 0000000..ca25678
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/angleButtonFocus.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/angleButtonFocusLost.png b/org.mihalis.opal/src/main/resources/images/angleButtonFocusLost.png
new file mode 100644
index 0000000..fe11498
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/angleButtonFocusLost.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/arrowGreenRight.png b/org.mihalis.opal/src/main/resources/images/arrowGreenRight.png
new file mode 100644
index 0000000..63b675c
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/arrowGreenRight.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/arrow_down.png b/org.mihalis.opal/src/main/resources/images/arrow_down.png
new file mode 100644
index 0000000..e448479
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/arrow_down.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/arrow_left.png b/org.mihalis.opal/src/main/resources/images/arrow_left.png
new file mode 100644
index 0000000..f53bc04
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/arrow_left.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/arrow_right.png b/org.mihalis.opal/src/main/resources/images/arrow_right.png
new file mode 100644
index 0000000..e5fa11e
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/arrow_right.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/arrow_up.png b/org.mihalis.opal/src/main/resources/images/arrow_up.png
new file mode 100644
index 0000000..bef99c4
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/arrow_up.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/category.png b/org.mihalis.opal/src/main/resources/images/category.png
new file mode 100644
index 0000000..6c479c8
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/category.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/close.png b/org.mihalis.opal/src/main/resources/images/close.png
new file mode 100644
index 0000000..1db6f6b
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/close.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/columnArrow.png b/org.mihalis.opal/src/main/resources/images/columnArrow.png
new file mode 100644
index 0000000..6425fff
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/columnArrow.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/description.png b/org.mihalis.opal/src/main/resources/images/description.png
new file mode 100644
index 0000000..dc2e9d5
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/description.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/double_down.png b/org.mihalis.opal/src/main/resources/images/double_down.png
new file mode 100644
index 0000000..806289c
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/double_down.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/double_left.png b/org.mihalis.opal/src/main/resources/images/double_left.png
new file mode 100644
index 0000000..176eb06
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/double_left.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/double_right.png b/org.mihalis.opal/src/main/resources/images/double_right.png
new file mode 100644
index 0000000..feafdf6
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/double_right.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/double_up.png b/org.mihalis.opal/src/main/resources/images/double_up.png
new file mode 100644
index 0000000..44990fa
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/double_up.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/fewerDetails.png b/org.mihalis.opal/src/main/resources/images/fewerDetails.png
new file mode 100644
index 0000000..c45d4ac
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/fewerDetails.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/h-slider-drag.png b/org.mihalis.opal/src/main/resources/images/h-slider-drag.png
new file mode 100644
index 0000000..2011d9b
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/h-slider-drag.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/h-slider-hover.png b/org.mihalis.opal/src/main/resources/images/h-slider-hover.png
new file mode 100644
index 0000000..9f0d039
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/h-slider-hover.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/h-slider-normal.png b/org.mihalis.opal/src/main/resources/images/h-slider-normal.png
new file mode 100644
index 0000000..bdc317f
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/h-slider-normal.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/h-slider-selected.png b/org.mihalis.opal/src/main/resources/images/h-slider-selected.png
new file mode 100644
index 0000000..b57ffe6
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/h-slider-selected.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/information.png b/org.mihalis.opal/src/main/resources/images/information.png
new file mode 100644
index 0000000..2c80c3f
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/information.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/light1.png b/org.mihalis.opal/src/main/resources/images/light1.png
new file mode 100644
index 0000000..1fb997a
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/light1.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/light2.png b/org.mihalis.opal/src/main/resources/images/light2.png
new file mode 100644
index 0000000..4e5edf8
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/light2.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/moreDetails.png b/org.mihalis.opal/src/main/resources/images/moreDetails.png
new file mode 100644
index 0000000..b8896c7
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/moreDetails.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/slider-drag.png b/org.mihalis.opal/src/main/resources/images/slider-drag.png
new file mode 100644
index 0000000..2d88c1a
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/slider-drag.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/slider-hover.png b/org.mihalis.opal/src/main/resources/images/slider-hover.png
new file mode 100644
index 0000000..e8ac5ad
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/slider-hover.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/slider-normal.png b/org.mihalis.opal/src/main/resources/images/slider-normal.png
new file mode 100644
index 0000000..4c5098c
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/slider-normal.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/slider-selected.png b/org.mihalis.opal/src/main/resources/images/slider-selected.png
new file mode 100644
index 0000000..9d19943
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/slider-selected.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/sort.png b/org.mihalis.opal/src/main/resources/images/sort.png
new file mode 100644
index 0000000..3851ff0
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/sort.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/stars/16.png b/org.mihalis.opal/src/main/resources/images/stars/16.png
new file mode 100644
index 0000000..aaf4c87
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/stars/16.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/stars/32.png b/org.mihalis.opal/src/main/resources/images/stars/32.png
new file mode 100644
index 0000000..8ae1a40
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/stars/32.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/stars/focus16.png b/org.mihalis.opal/src/main/resources/images/stars/focus16.png
new file mode 100644
index 0000000..15e1d05
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/stars/focus16.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/stars/focus32.png b/org.mihalis.opal/src/main/resources/images/stars/focus32.png
new file mode 100644
index 0000000..2b17bab
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/stars/focus32.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/stars/mark-focus16.png b/org.mihalis.opal/src/main/resources/images/stars/mark-focus16.png
new file mode 100644
index 0000000..92dfc2f
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/stars/mark-focus16.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/stars/mark-focus32.png b/org.mihalis.opal/src/main/resources/images/stars/mark-focus32.png
new file mode 100644
index 0000000..92b754e
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/stars/mark-focus32.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/stars/mark16.png b/org.mihalis.opal/src/main/resources/images/stars/mark16.png
new file mode 100644
index 0000000..5c8a3c6
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/stars/mark16.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/stars/mark32.png b/org.mihalis.opal/src/main/resources/images/stars/mark32.png
new file mode 100644
index 0000000..0d2f615
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/stars/mark32.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/images/trash.png b/org.mihalis.opal/src/main/resources/images/trash.png
new file mode 100644
index 0000000..9bd926d
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/images/trash.png
Binary files differ
diff --git a/org.mihalis.opal/src/main/resources/resources/opal.properties b/org.mihalis.opal/src/main/resources/resources/opal.properties
new file mode 100644
index 0000000..94a25f2
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/resources/opal.properties
@@ -0,0 +1,58 @@
+Ok=OK
+Cancel=Cancel
+Close=Close
+Yes=Yes
+No=No
+MoreDetails=More Details
+FewerDetails=Fewer Details
+Details=Details
+Information=Information
+Error=Error
+Question=Question
+Warning=Warning
+Exception=Exception
+Choice=Choice
+Select=Select
+Input=Input
+ApplicationError=Application Error
+megabytes=Mb
+performGC=Perform GC
+login=Login
+name=Name
+password=Password
+rememberPassword=Remember password
+loginFailed=Login failed
+tipOfTheDay=Tip of the day
+didYouKnow=Did you know...
+showTipAtStartup=Show Tip at startup
+previousTip=< Previous Tip
+nextTip=Next Tip >
+choose=Choose
+preferences=Preferences
+validURL=Please enter a valid URL
+chooseDirectory=Please choose a directory
+bold=bold
+italic=italic
+category.shortDescription = Toggle between Category view and Flat list view
+description.shortDescription = Show/Hide the Description pane
+sort.shortDescription = Sort Properties and Categories by Name
+property=Property
+value=Value
+editProperty=Edit property
+width=Width
+height=Height
+top=Top
+bottom=Bottom
+left=Left
+right=Right
+eraseProperty=Erase the value of the property
+physicalMemory=Physical Memory
+heapMemory=Heap Memory
+threads=Threads
+cpuUsage=CPU Usage
+peak=Peak
+mb=MB
+calculator.dividebyzero=Cannot divide by zero !
+calculator.invalid=Invalid input for function !
+multichoice.message=The entry %s is invalid, please check it!
+multichoice.message.plural=The entries %s are invalid, please check it! \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/resources/resources/opal_de_DE.properties b/org.mihalis.opal/src/main/resources/resources/opal_de_DE.properties
new file mode 100644
index 0000000..4b6e6c0
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/resources/opal_de_DE.properties
@@ -0,0 +1,58 @@
+OK=OK
+Cancel=Abbrechen
+Close=Schließen
+Yes=Ja
+No=Nein
+MoreDetails=Weitere Details
+FewerDetails=Weniger Details
+Details=Details
+Information=Information
+Error=Fehler
+Question=Frage
+Warning=Warnung
+Exception=Ausnahme
+Choice=Auswahl
+Select=Auswählen
+Input=Eingabe
+ApplicationError=Application Error
+megabytes=Mb
+performGC=Perform GC
+login=Login
+name=Name
+password=Passwort
+rememberPassword=Passwort merken
+loginFailed=Login failed
+tipOfTheDay=Tip of the day
+didYouKnow=Did you know...
+showTipAtStartup=Show Tip at startup
+previousTip=< Previous Tip
+nextTip=Next Tip >
+choose=Choose
+preferences=Preferences
+validURL=Please enter a valid URL
+chooseDirectory=Please choose a directory
+bold=bold
+italic=italic
+category.shortDescription = Toggle between Category view and Flat list view
+description.shortDescription = Show/Hide the Description pane
+sort.shortDescription = Sort Properties and Categories by Name
+property=Property
+value=Value
+editProperty=Edit property
+width=Width
+height=Height
+top=Top
+bottom=Bottom
+left=Left
+right=Right
+eraseProperty=Erase the value of the property
+physicalMemory=Physical Memory
+heapMemory=Heap Memory
+threads=Threads
+cpuUsage=CPU Usage
+peak=Peak
+mb=MB
+calculator.dividebyzero=Cannot divide by zero !
+calculator.invalid=Invalid input for function !
+multichoice.message=The entry %s is invalid, please check it!
+multichoice.message.plural=The entries %s are invalid, please check it! \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/resources/resources/opal_es_ES.properties b/org.mihalis.opal/src/main/resources/resources/opal_es_ES.properties
new file mode 100644
index 0000000..a778ce9
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/resources/opal_es_ES.properties
@@ -0,0 +1,58 @@
+Ok=OK
+Cancel=Cancelar
+Close=Cerrar
+Yes=Sí
+No=No
+MoreDetails=Más detalles
+FewerDetails=Pocos detalles
+Details=Detalles
+Information=Información
+Error=Error
+Question=Pregunta
+Warning=Advertencia
+Exception=Excepción
+Choice=Elección
+Select=Seleccione
+Input=Entrada
+ApplicationError=Error de la aplicación
+megabytes=Mb
+performGC=Ejecutar GC
+login=Conexión
+name=Nombre
+password=Contraseña
+rememberPassword=Recordar contraseña
+loginFailed=Fallo en la conexión
+tipOfTheDay=Consejo diario
+didYouKnow=Sabias que...?
+showTipAtStartup=Mostrar consejos al inicio
+previousTip=<Consejo anterior
+nextTip=Siguiente consejo>
+choose=Elegir
+preferences=Preferencias
+validURL=Por favor, introduzca una URL válida
+chooseDirectory=Por favor, escoge un directorio
+bold=negrita
+italic=cursiva
+category.shortDescription = Toggle between Category view and Flat list view
+description.shortDescription = Show/Hide the Description pane
+sort.shortDescription = Sort Properties and Categories by Name
+property=Property
+value=Value
+editProperty=Edit property
+width=Width
+height=Height
+top=Top
+bottom=Bottom
+left=Left
+right=Right
+eraseProperty=Erase the value of the property
+physicalMemory=Physical Memory
+heapMemory=Heap Memory
+threads=Threads
+cpuUsage=CPU Usage
+peak=Peak
+mb=MB
+calculator.dividebyzero=Cannot divide by zero !
+calculator.invalid=Invalid input for function !
+multichoice.message=The entry %s is invalid, please check it!
+multichoice.message.plural=The entries %s are invalid, please check it! \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/resources/resources/opal_fr_FR.properties b/org.mihalis.opal/src/main/resources/resources/opal_fr_FR.properties
new file mode 100644
index 0000000..5614c5a
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/resources/opal_fr_FR.properties
@@ -0,0 +1,58 @@
+OK=OK
+Cancel=Annuler
+Close=Fermer
+Yes=Oui
+No=Non
+MoreDetails=Plus de détails
+FewerDetails=Moins de détails
+Details=Détails
+Information=Information
+Error=Erreur
+Question=Question
+Warning=Avertissement
+Exception=Exception
+Choice=Choix
+Select=Sélection
+Input=Entrée
+ApplicationError=Erreur applicative
+megabytes=Mo
+performGC=Lancer le ramasse-miettes (GC)
+login=Identification
+name=Nom
+password=Mot de passe
+rememberPassword=Se souvenir de mon mot de passe
+loginFailed=Echec de l'authentification
+tipOfTheDay=Astuce du jour
+didYouKnow=Le savez-vous ?
+showTipAtStartup=Afficher les astuces au démarrage
+previousTip=< Astuce précédente
+nextTip=Astuce suivante >
+choose=Choisir
+preferences=Préférences
+validURL=Merci de saisir une URL valide s'il vous plait
+chooseDirectory=Veuillez choisir un répertoire
+bold=gras
+italic=italique
+category.shortDescription = Alterner entre vue par Cat\u00e9gorie et liste
+description.shortDescription = Afficher/Cacher le panneau de Description
+sort.shortDescription = Trier les Propri\u00e9t\u00e9s et Cat\u00e9gories par Nom
+property=Propriété
+value=Valeur
+editProperty=Edition de la valeur de la propriété
+width=Largeur
+height=Hauteur
+top=Haut
+bottom=Bas
+left=Gauche
+right=Droite
+eraseProperty=Efface la valeur de cette propriété
+physicalMemory=Mémoire physique
+heapMemory=Mémoire Heap
+threads=Threads
+cpuUsage=Utilisation CPU
+peak=Max
+mb=Mo
+calculator.dividebyzero=Division par zéro impossible !
+calculator.invalid=Entrée invalide pour cette fonction !
+multichoice.message=L'entrée %s n'est pas valide, merci de la v\u00e9rifier !
+multichoice.message.plural=Les entr\u00e9es %s ne sont pas valides, merci de les v\u00e9rifier! \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/resources/resources/opal_it_IT.properties b/org.mihalis.opal/src/main/resources/resources/opal_it_IT.properties
new file mode 100644
index 0000000..70f716d
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/resources/opal_it_IT.properties
@@ -0,0 +1,58 @@
+OK=OK
+Cancel=Annulla
+Close=Chiudi
+Yes=Si
+No=No
+MoreDetails=Pi\u00F9 Dettagli
+FewerDetails=Meno Dettagli
+Details=Dettagli
+Information=Informazione
+Error=Errore
+Question=Domanda
+Warning=Avvertenza
+Exception=Eccezione
+Choice=Scelta
+Select=Seleziona
+Input=Input
+ApplicationError=Errore di applicazione
+megabytes=Mb
+performGC=Perform GC
+login=Accesso
+name=Nome
+password=Password
+rememberPassword=Remember password
+loginFailed=Login failed
+tipOfTheDay=Tip of the day
+didYouKnow=Did you know...
+showTipAtStartup=Show Tip at startup
+previousTip=< Previous Tip
+nextTip=Next Tip >
+choose=Choose
+preferences=Preferences
+validURL=Please enter a valid URL
+chooseDirectory=Please choose a directory
+bold=bold
+italic=italic
+category.shortDescription = Toggle between Category view and Flat list view
+description.shortDescription = Show/Hide the Description pane
+sort.shortDescription = Sort Properties and Categories by Name
+property=Property
+value=Value
+editProperty=Edit property
+width=Width
+height=Height
+top=Top
+bottom=Bottom
+left=Left
+right=Right
+eraseProperty=Erase the value of the property
+physicalMemory=Physical Memory
+heapMemory=Heap Memory
+threads=Threads
+cpuUsage=CPU Usage
+peak=Peak
+mb=MB
+calculator.dividebyzero=Cannot divide by zero !
+calculator.invalid=Invalid input for function !
+multichoice.message=The entry %s is invalid, please check it!
+multichoice.message.plural=The entries %s are invalid, please check it! \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/resources/resources/opal_nl_NL.properties b/org.mihalis.opal/src/main/resources/resources/opal_nl_NL.properties
new file mode 100644
index 0000000..5ea06ed
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/resources/opal_nl_NL.properties
@@ -0,0 +1,58 @@
+Ok=OK
+Cancel=Annuleren
+Close=Sluiten
+Yes=Ja
+No=Nee
+MoreDetails=Meer info
+FewerDetails=Minder info
+Details=Info
+Information=Informatie
+Error=Fout
+Question=Vraag
+Warning=Waarschuwing
+Exception=Exception
+Choice=Kies
+Select=Kies
+Input=Invoer
+ApplicationError=Fout in toepassing
+megabytes=Mb
+performGC=Voer GC uit
+login=Login
+name=Naam
+password=Wachtwoord
+rememberPassword=Wachtwoord onthouden
+loginFailed=Inloggen mislukt
+tipOfTheDay=Tip van de dag
+didYouKnow=Wisu u dat...
+showTipAtStartup=Tips weergeven bij opstarten
+previousTip=< Vorige Tip
+nextTip=Volgende Tip >
+choose=Kies
+preferences=Voorkeuren
+validURL=Geef een geldige URL op
+chooseDirectory=Kies een map
+bold=vet
+italic=cursief
+category.shortDescription = Wissel tussen weergave per category en lijst weergave
+description.shortDescription = Toon/Verberg omschrijving
+sort.shortDescription = Sorteer eigenschappen en categorie\u00ebn op naam
+property=Eigenschap
+value=Waarde
+editProperty=Bewerk eigenschap
+width=Breedte
+height=Hoogte
+top=Bovenkant
+bottom=Onderkant
+left=Links
+right=Rechts
+eraseProperty=Wis de waarde van de eigenschap
+physicalMemory=Physical Memory
+heapMemory=Heap Memory
+threads=Threads
+cpuUsage=CPU Usage
+peak=Peak
+mb=MB
+calculator.dividebyzero=Cannot divide by zero !
+calculator.invalid=Invalid input for function !
+multichoice.message=The entry %s is invalid, please check it!
+multichoice.message.plural=The entries %s are invalid, please check it! \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/resources/resources/opal_pl_PL.properties b/org.mihalis.opal/src/main/resources/resources/opal_pl_PL.properties
new file mode 100644
index 0000000..dc3e756
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/resources/opal_pl_PL.properties
@@ -0,0 +1,58 @@
+Ok=OK
+Cancel=Anuluj
+Close=Zamknij
+Yes=Tak
+No=Nie
+MoreDetails=Więcej szczegółów
+FewerDetails=Mniej szczegółów
+Details=Szczegóły
+Information=Informacja
+Error=BÅ‚Ä…d
+Question=Pytanie
+Warning=Ostrzeżenie
+Exception=WyjÄ…tek
+Choice=Wybór
+Select=Wybór
+Input=Wprowadzanie
+ApplicationError=BÅ‚Ä…d aplikacji
+megabytes=Mb
+performGC=Wykonaj GC
+login=Login
+name=Nazwa
+password=Hasło
+rememberPassword=Zapamiętaj hasło
+loginFailed=Logowanie nie powiodło się
+tipOfTheDay=Porada dnia
+didYouKnow=Czy wiesz, że...
+showTipAtStartup=Wyświetl Poradę dnia przy starcie
+previousTip=< Poprzednia Porada
+nextTip=Następna Porada >
+choose=Wybierz
+preferences=Preferencje
+validURL=Wpisz poprawny adres URL
+chooseDirectory=Proszę wybrać katalog
+bold=pogrubienie
+italic=kursywa
+category.shortDescription = Przełącz pomiędzy widokiem kategorii a widokiem płaskiej listy
+description.shortDescription = Pokaż/Ukryj panel Opisu
+sort.shortDescription = Sortuj Właściwości i Kategorie po Nazwie
+property=Właściwość
+value=Wartość
+editProperty=Edytuj właściwość
+width=Szerokość
+height=Wysokość
+top=Góra
+bottom=Dół
+left=Lewo
+right=Prawo
+eraseProperty=Wymaż wartość właściwości
+physicalMemory=Pamięć Fizyczna
+heapMemory=Sterta Pamięci
+threads=WÄ…tki
+cpuUsage=Wykorzystanie CPU
+peak=Pik
+mb=MB
+calculator.dividebyzero=Nie można dzielić przez zero !
+calculator.invalid=Nieprawidłowe parametry funkcji !
+multichoice.message=The entry %s is invalid, please check it!
+multichoice.message.plural=The entries %s are invalid, please check it! \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/resources/resources/opal_pt_BR.properties b/org.mihalis.opal/src/main/resources/resources/opal_pt_BR.properties
new file mode 100644
index 0000000..7060883
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/resources/opal_pt_BR.properties
@@ -0,0 +1,58 @@
+Ok=OK
+Cancel=Cancelar
+Close=Fechar
+Yes=Sim
+No=Não
+MoreDetails=Mais detalhes
+FewerDetails=Menos detalhes
+Details=Detalhes
+Information=Informação
+Error=Erro
+Question=Questão
+Warning=Aviso
+Exception=Exceção
+Choice=Escolher
+Select=Selecionar
+Input=Entrar
+ApplicationError=Erro da aplicação
+megabytes=Mb
+performGC=Perform GC
+login=Login
+name=Name
+password=Password
+rememberPassword=Remember password
+loginFailed=Login failed
+tipOfTheDay=Tip of the day
+didYouKnow=Did you know...
+showTipAtStartup=Show Tip at startup
+previousTip=< Previous Tip
+nextTip=Next Tip >
+choose=Choose
+preferences=Preferences
+validURL=Please enter a valid URL
+chooseDirectory=Please choose a directory
+bold=bold
+italic=italic
+category.shortDescription = Toggle between Category view and Flat list view
+description.shortDescription = Show/Hide the Description pane
+sort.shortDescription = Sort Properties and Categories by Name
+property=Property
+value=Value
+editProperty=Edit property
+width=Width
+height=Height
+top=Top
+bottom=Bottom
+left=Left
+right=Right
+eraseProperty=Erase the value of the property
+physicalMemory=Physical Memory
+heapMemory=Heap Memory
+threads=Threads
+cpuUsage=CPU Usage
+peak=Peak
+mb=MB
+calculator.dividebyzero=Cannot divide by zero !
+calculator.invalid=Invalid input for function !
+multichoice.message=The entry %s is invalid, please check it!
+multichoice.message.plural=The entries %s are invalid, please check it! \ No newline at end of file
diff --git a/org.mihalis.opal/src/main/resources/resources/opal_zh_CN.properties b/org.mihalis.opal/src/main/resources/resources/opal_zh_CN.properties
new file mode 100644
index 0000000..09c5762
--- /dev/null
+++ b/org.mihalis.opal/src/main/resources/resources/opal_zh_CN.properties
@@ -0,0 +1,58 @@
+Ok=\u786e\u5b9a
+Cancel=\u653e\u5f03
+Close=\u5173\u95ed
+Yes=\u662f
+No=\u5426
+MoreDetails=\u8be6\u7ec6\u4fe1\u606f
+FewerDetails=\u7b80\u660e\u4fe1\u606f
+Details=\u4fe1\u606f
+Information=\u4fe1\u606f
+Error=\u9519\u8bef
+Question=\u95ee\u9898
+Warning=\u8b66\u544a
+Exception=\u5f02\u5e38
+Choice=\u9009\u9879
+Select=\u9009\u62e9
+Input=\u8f93\u5165
+ApplicationError=Application Error
+megabytes=Mb
+performGC=Perform GC
+login=Login
+name=Name
+password=Password
+rememberPassword=Remember password
+loginFailed=Login failed
+tipOfTheDay=Tip of the day
+didYouKnow=Did you know...
+showTipAtStartup=Show Tip at startup
+previousTip=< Previous Tip
+nextTip=Next Tip >
+choose=Choose
+preferences=Preferences
+validURL=Please enter a valid URL
+chooseDirectory=Please choose a directory
+bold=bold
+italic=italic
+category.shortDescription = Toggle between Category view and Flat list view
+description.shortDescription = Show/Hide the Description pane
+sort.shortDescription = Sort Properties and Categories by Name
+property=Property
+value=Value
+editProperty=Edit property
+width=Width
+height=Height
+top=Top
+bottom=Bottom
+left=Left
+right=Right
+eraseProperty=Erase the value of the property
+physicalMemory=Physical Memory
+heapMemory=Heap Memory
+threads=Threads
+cpuUsage=CPU Usage
+peak=Peak
+mb=MB
+calculator.dividebyzero=Cannot divide by zero !
+calculator.invalid=Invalid input for function !
+multichoice.message=The entry %s is invalid, please check it!
+multichoice.message.plural=The entries %s are invalid, please check it! \ No newline at end of file
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/angles/AngleSliderSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/angles/AngleSliderSnippet.java
new file mode 100644
index 0000000..fd334c0
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/angles/AngleSliderSnippet.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * 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 org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.utils.SimpleSelectionAdapter;
+
+/**
+ * A simple snipper for the AngleSlider widget
+ *
+ */
+public class AngleSliderSnippet {
+
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(2, false));
+
+ final AngleSlider angleSlider = new AngleSlider(shell, SWT.NONE);
+ angleSlider.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false, 2, 1));
+
+ final Button button = new Button(shell, SWT.CHECK);
+ button.setText("Enabled");
+ button.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false, 2, 1));
+ button.setSelection(true);
+ button.addSelectionListener(new SimpleSelectionAdapter() {
+
+ @Override
+ public void handle(final SelectionEvent e) {
+ angleSlider.setEnabled(button.getSelection());
+ }
+ });
+
+ final Label label = new Label(shell, SWT.NONE);
+ label.setText("Value :");
+ label.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));
+
+ final Text text = new Text(shell, SWT.READ_ONLY | SWT.BORDER);
+ text.setText("" + angleSlider.getSelection());
+ text.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+ angleSlider.addSelectionListener(new SimpleSelectionAdapter() {
+
+ @Override
+ public void handle(final SelectionEvent e) {
+ text.setText("" + angleSlider.getSelection());
+
+ }
+ });
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/BreadcrumbSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/BreadcrumbSnippet.java
new file mode 100644
index 0000000..442e407
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/BreadcrumbSnippet.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * 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 org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A simple snippet for the breadcrumb Widget
+ */
+public class BreadcrumbSnippet {
+
+ private static Image[] images;
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("BreakCrumb Snippet");
+ shell.setLayout(new GridLayout(2, false));
+
+ createImages();
+
+ createLabelsBreadCrumb(shell);
+ createButtonsBreadCrumb(shell);
+ createButtonsIconsBreadCrumb(shell);
+ createToggleButtonsBreadCrumb(shell);
+
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+
+ }
+
+ private static void createImages() {
+ images = new Image[5];
+ final String[] fileNames = new String[] { "add.png", "bell.png", "feed.png", "house.png", "script.png" };
+ for (int i = 0; i < 5; i++) {
+ final Image image = new Image(Display.getCurrent(), BreadcrumbSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/breadcrumb/" + fileNames[i]));
+ images[i] = image;
+ }
+ }
+
+ private static void createLabelsBreadCrumb(final Shell shell) {
+ final Label label = new Label(shell, SWT.NONE);
+ label.setText("Label breadcrumb:");
+ label.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ createBreadcrumb(shell, SWT.BORDER, SWT.CENTER, false);
+// new Label(shell, SWT.NONE);
+
+ createBreadcrumb(shell, SWT.NONE, SWT.CENTER, false);
+ }
+
+ private static void createBreadcrumb(final Shell shell, final int breadCrumbArgument, final int itemArgument, final boolean showImages) {
+ final Breadcrumb bc = new Breadcrumb(shell, breadCrumbArgument);
+ bc.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+
+ for (int i = 1; i < 5; i++) {
+ final BreadcrumbItem item = new BreadcrumbItem(bc, itemArgument);
+ item.setText("Label " + String.valueOf(i));
+ if (showImages) {
+ item.setImage(images[i]);
+ item.setSelectionImage(images[i]);
+ }
+ item.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ System.out.println("Click !");
+ }
+
+ });
+ }
+ }
+
+ private static void createButtonsBreadCrumb(final Shell shell) {
+ final Label label = new Label(shell, SWT.NONE);
+ label.setText("Buttons breadcrumb:");
+ label.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ createBreadcrumb(shell, SWT.BORDER, SWT.CENTER | SWT.PUSH, false);
+// new Label(shell, SWT.NONE);
+
+ createBreadcrumb(shell, SWT.NONE, SWT.CENTER | SWT.PUSH, false);
+ }
+
+ private static void createButtonsIconsBreadCrumb(final Shell shell) {
+ final Label label = new Label(shell, SWT.NONE);
+ label.setText("Buttons breadcrumb:");
+ label.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ createBreadcrumb(shell, SWT.BORDER, SWT.CENTER | SWT.PUSH, true);
+// new Label(shell, SWT.NONE);
+
+ createBreadcrumb(shell, SWT.NONE, SWT.CENTER | SWT.PUSH, true);
+ }
+
+ private static void createToggleButtonsBreadCrumb(final Shell shell) {
+ final Label label = new Label(shell, SWT.NONE);
+ label.setText("Toggle buttons breadcrumb:");
+ label.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ createBreadcrumb(shell, SWT.BORDER, SWT.CENTER | SWT.TOGGLE, false);
+// new Label(shell, SWT.NONE);
+
+ createBreadcrumb(shell, SWT.NONE, SWT.CENTER | SWT.TOGGLE, false);
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/add.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/add.png
new file mode 100644
index 0000000..6332fef
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/add.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/bell.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/bell.png
new file mode 100644
index 0000000..6e0015d
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/bell.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/feed.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/feed.png
new file mode 100644
index 0000000..315c4f4
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/feed.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/house.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/house.png
new file mode 100644
index 0000000..fed6221
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/house.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/script.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/script.png
new file mode 100644
index 0000000..0f9ed4d
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/breadcrumb/script.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/brushedMetalComposite/BrushedMetalCompositePlayer.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/brushedMetalComposite/BrushedMetalCompositePlayer.java
new file mode 100644
index 0000000..9034f9e
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/brushedMetalComposite/BrushedMetalCompositePlayer.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * 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 org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.ColorDialog;
+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;
+import org.eclipse.swt.widgets.Slider;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * This snippet demonstrates the brushed metal composite and allows user to set
+ * up the parameters
+ *
+ */
+public class BrushedMetalCompositePlayer {
+
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(3, false));
+
+ final BrushedMetalComposite bmc = new BrushedMetalComposite(shell, SWT.NONE);
+ final GridData gdBmc = new GridData(GridData.FILL, GridData.FILL, true, true, 3, 1);
+ gdBmc.widthHint = gdBmc.heightHint = 300;
+ bmc.setLayoutData(gdBmc);
+
+ // Displays the control used to set up the parameters
+ createSlider(shell, bmc, "Blur", 10f, false, null);
+ createSlider(shell, bmc, "Amount of noise", 0.1f, true, null);
+ createSlider(shell, bmc, "Shine", 0.1f, true, null);
+
+ createColorSelector(shell, bmc);
+ createMonochromeButton(shell, bmc);
+
+ shell.pack();
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+ private static void createSlider(final Shell shell, final BrushedMetalComposite bmc, final String text, final float defaultValue, final boolean isDecimal, final Listener listener) {
+ final Label label = new Label(shell, SWT.NONE);
+ label.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ label.setText(text);
+
+ final Slider slider = new Slider(shell, SWT.HORIZONTAL);
+ slider.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+ slider.setMinimum(0);
+ slider.setMaximum(110);
+
+ final Text txt = new Text(shell, SWT.SINGLE | SWT.READ_ONLY);
+ final GridData gd = new GridData(GridData.FILL, GridData.CENTER, false, false);
+ gd.widthHint = 50;
+ txt.setLayoutData(gd);
+
+ if (isDecimal) {
+ slider.setSelection((int) (defaultValue * 100));
+ txt.setText("" + defaultValue);
+ } else {
+ slider.setSelection((int) defaultValue);
+ txt.setText("" + (int) defaultValue);
+ }
+
+ slider.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ if (isDecimal) {
+ final float newValue = slider.getSelection() / 100f;
+ if (text.startsWith("Amount")) {
+ bmc.setAmount(newValue);
+ } else {
+ bmc.setShine(newValue);
+ }
+ txt.setText("" + newValue);
+ } else {
+ bmc.setRadius(slider.getSelection());
+ txt.setText("" + slider.getSelection());
+ }
+ }
+ });
+
+ if (listener != null) {
+ slider.addListener(SWT.Selection, listener);
+ }
+ }
+
+ private static void createColorSelector(final Shell shell, final BrushedMetalComposite bmc) {
+ final Label label = new Label(shell, SWT.NONE);
+ label.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ label.setText("Color :");
+
+ final Text colorSelector = new Text(shell, SWT.BORDER | SWT.READ_ONLY);
+ colorSelector.setText("Click to pick a color");
+ final Cursor cursor = new Cursor(shell.getDisplay(), SWT.CURSOR_ARROW);
+ colorSelector.setCursor(cursor);
+ shell.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ cursor.dispose();
+ }
+ });
+
+ final Color color = bmc.getColor();
+ shell.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ color.dispose();
+ }
+ });
+
+ colorSelector.setBackground(color);
+ colorSelector.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false, 2, 1));
+
+ colorSelector.addListener(SWT.MouseUp, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ final ColorDialog dialog = new ColorDialog(shell);
+ final RGB rgb = dialog.open();
+ if (rgb == null) {
+ return;
+ }
+
+ final Color color = new Color(shell.getDisplay(), rgb);
+ shell.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ color.dispose();
+ }
+ });
+ bmc.setColor(color);
+ colorSelector.setBackground(color);
+ }
+ });
+
+ }
+
+ private static void createMonochromeButton(final Shell shell, final BrushedMetalComposite bmc) {
+ final Button button = new Button(shell, SWT.CHECK);
+ button.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false, 3, 1));
+ button.setText("Monochrome ?");
+ button.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ bmc.setMonochrome(!button.getSelection());
+ }
+ });
+
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/brushedMetalComposite/SnippetBrushedMetalComposite.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/brushedMetalComposite/SnippetBrushedMetalComposite.java
new file mode 100644
index 0000000..12653aa
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/brushedMetalComposite/SnippetBrushedMetalComposite.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * 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 org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * This snippet demonstrates the brushed metal composite
+ *
+ */
+public class SnippetBrushedMetalComposite {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setBackgroundMode(SWT.INHERIT_DEFAULT);
+ final FillLayout layout1 = new FillLayout(SWT.VERTICAL);
+ layout1.marginWidth = layout1.marginHeight = 10;
+ shell.setLayout(layout1);
+
+ // Displays the composite
+ final BrushedMetalComposite bmc = new BrushedMetalComposite(shell, SWT.NONE);
+
+ // And the content
+ final RowLayout layout2 = new RowLayout(SWT.VERTICAL);
+ layout2.marginWidth = layout2.marginHeight = layout2.spacing = 10;
+ bmc.setLayout(layout2);
+ for (int i = 0; i < 8; i++) {
+ final Button button = new Button(bmc, SWT.RADIO);
+ button.setText("Button " + i);
+ }
+
+ // Open the shell
+ shell.setSize(400, 400);
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/calculator/CalculatorComboSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/calculator/CalculatorComboSnippet.java
new file mode 100644
index 0000000..bb94e70
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/calculator/CalculatorComboSnippet.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * 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.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A simple snippet for the CalculatorCombo Widget
+ */
+public class CalculatorComboSnippet {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(2, false));
+
+ final Label label = new Label(shell, SWT.NONE);
+ label.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ label.setText("Calculator combo:");
+
+ final CalculatorCombo combo = new CalculatorCombo(shell, SWT.NONE);
+ combo.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, true, false));
+
+ combo.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(final ModifyEvent e) {
+ System.out.println("New value is " + combo.getValue());
+
+ }
+ });
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/calculator/CalculatorSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/calculator/CalculatorSnippet.java
new file mode 100644
index 0000000..f89f7e8
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/calculator/CalculatorSnippet.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A simple snippet for the Calculator Widget
+ */
+public class CalculatorSnippet {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout(SWT.VERTICAL));
+
+ final Calculator calc = new Calculator(shell, SWT.NONE);
+
+ calc.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(final ModifyEvent e) {
+ System.out.println("New value is " + calc.getValue());
+
+ }
+ });
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/checkBoxGroup/SnippetCheckBoxGroup.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/checkBoxGroup/SnippetCheckBoxGroup.java
new file mode 100644
index 0000000..277b3ba
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/checkBoxGroup/SnippetCheckBoxGroup.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * 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.checkBoxGroup;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the checkBoxGroup widget
+ *
+ */
+public class SnippetCheckBoxGroup {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setBackgroundMode(SWT.INHERIT_DEFAULT);
+ final FillLayout layout1 = new FillLayout(SWT.VERTICAL);
+ layout1.marginWidth = layout1.marginHeight = 10;
+ shell.setLayout(layout1);
+
+ // Displays the group
+ final CheckBoxGroup group = new CheckBoxGroup(shell, SWT.NONE);
+ group.setLayout(new GridLayout(4, false));
+ group.setText("Use proxy server");
+
+ final Composite content = group.getContent();
+
+ final Label lblServer = new Label(content, SWT.NONE);
+ lblServer.setText("Server:");
+ lblServer.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ final Text txtServer = new Text(content, SWT.NONE);
+ txtServer.setText("proxy.host.com");
+ txtServer.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+
+ final Label lblPort = new Label(content, SWT.NONE);
+ lblPort.setText("Port:");
+ lblPort.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ final Text txtPort = new Text(content, SWT.NONE);
+ txtPort.setText("1234");
+ txtPort.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+
+ final Label lblUser = new Label(content, SWT.NONE);
+ lblUser.setText("User ID:");
+ lblUser.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ final Text txtUser = new Text(content, SWT.NONE);
+ txtUser.setText("MyName");
+ txtUser.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+
+ final Label lblPassword = new Label(content, SWT.NONE);
+ lblPassword.setText("Password:");
+ lblPassword.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ final Text txtPassword = new Text(content, SWT.PASSWORD);
+ txtPassword.setText("password");
+ txtPassword.setEnabled(false);
+ txtPassword.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+
+ // Open the shell
+ shell.setSize(640, 360);
+ SWTGraphicUtil.centerShell(shell);
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/columns/ColumnsSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/columns/ColumnsSnippet.java
new file mode 100644
index 0000000..ff6500b
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/columns/ColumnsSnippet.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * 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.columns;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.opalDialog.Dialog;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the ColumnBrowser widget
+ */
+public class ColumnsSnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(2, false));
+
+ final ColumnBrowserWidget cbw = new ColumnBrowserWidget(shell, SWT.NONE);
+ cbw.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1));
+
+ final ColumnItem item = createColors(cbw);
+ createSports(cbw);
+
+ createShowSelectionButton(shell, cbw);
+ createForceSelection(shell, cbw, item);
+
+ shell.setSize(640, 350);
+ shell.pack();
+ shell.open();
+ SWTGraphicUtil.centerShell(shell);
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+ private static ColumnItem createColors(final ColumnBrowserWidget cbw) {
+ final ColumnItem root = new ColumnItem(cbw);
+ root.setText("Colors");
+
+ final ColumnItem b = new ColumnItem(root);
+ b.setText("b");
+
+ final ColumnItem bl = new ColumnItem(b);
+ bl.setText("l");
+
+ final ColumnItem blu = new ColumnItem(bl);
+ blu.setText("u");
+
+ final ColumnItem blue = new ColumnItem(blu);
+ blue.setText("e");
+
+ final ColumnItem r = new ColumnItem(root);
+ r.setText("r");
+
+ final ColumnItem re = new ColumnItem(r);
+ re.setText("e");
+
+ final ColumnItem red = new ColumnItem(re);
+ red.setText("d");
+
+ final ColumnItem ro = new ColumnItem(r);
+ ro.setText("o");
+
+ final ColumnItem ros = new ColumnItem(ro);
+ ros.setText("s");
+
+ final ColumnItem rose = new ColumnItem(ros);
+ rose.setText("e");
+
+ final ColumnItem g = new ColumnItem(root);
+ g.setText("g");
+
+ final ColumnItem gr = new ColumnItem(g);
+ gr.setText("r");
+
+ final ColumnItem gre = new ColumnItem(gr);
+ gre.setText("e");
+
+ final ColumnItem gree = new ColumnItem(gre);
+ gree.setText("e");
+
+ final ColumnItem green = new ColumnItem(gree);
+ green.setText("n");
+
+ return green;
+
+ }
+
+ private static void createSports(final ColumnBrowserWidget cbw) {
+ final ColumnItem root = new ColumnItem(cbw);
+ root.setText("Sports");
+
+ final ColumnItem football = new ColumnItem(root);
+ football.setText("Football");
+
+ final ColumnItem rugby = new ColumnItem(root);
+ rugby.setText("Rugby");
+
+ final ColumnItem handball = new ColumnItem(root);
+ handball.setText("Hand Ball");
+
+ }
+
+ private static void createShowSelectionButton(final Shell shell, final ColumnBrowserWidget cbw) {
+ final Button button = new Button(shell, SWT.PUSH);
+ button.setLayoutData(new GridData(GridData.END, GridData.FILL, true, false));
+ button.setText("Show selection");
+
+ button.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ Dialog.inform("Selection", "You have selected " + (cbw.getSelection() == null ? "nothing" : cbw.getSelection().getText()));
+ }
+ });
+
+ }
+
+ private static void createForceSelection(final Shell shell, final ColumnBrowserWidget cbw, final ColumnItem item) {
+ final Button button = new Button(shell, SWT.PUSH);
+ button.setLayoutData(new GridData(GridData.END, GridData.FILL, false, false));
+ button.setText("Force selection");
+
+ button.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ cbw.select(item);
+ }
+ });
+
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumnsSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumnsSnippet.java
new file mode 100644
index 0000000..3133643
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/dynamictablecolumns/DynamicTableColumnsSnippet.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * 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.Random;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+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.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TableItem;
+
+/**
+ *
+ * DynamicColumnsSnippet.
+ *
+ */
+public final class DynamicTableColumnsSnippet {
+
+ private static int idCount = 1;
+
+ private static String[] firstNameSet = { "Luis Carlos", "Laurent", "Getulio", "Nicholas" };
+ private static String[] lastNameSet = { "Moreira da Costa", "Caron", "Moreira da Costa", "Rocha da Costa" };
+ private static String[] birthDateSet = { "1967", "1974", "1939", "2001" };
+
+ private static Shell shell;
+
+ private static DynamicTable tblDyn;
+ private static DynamicTableColumn tblcId;
+ private static DynamicTableColumn tblcFirstName;
+ private static DynamicTableColumn tblcLastName;
+ private static DynamicTableColumn tblcAge;
+
+ private static Composite pnlButtons;
+ private static Button btnAdd;
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ shell = new Shell(display);
+ shell.setText("DynamicColumns SWT Usage Snippet");
+ final GridLayout layout = new GridLayout(2, false);
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ shell.setLayout(layout);
+
+ createContents();
+
+ // Initial Content
+ createPerson(0);
+ createPerson(1);
+ createPerson(2);
+ createPerson(3);
+ createPerson(3);
+ createPerson(3);
+
+ shell.open();
+ shell.pack();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+ /**
+ * Create contents
+ */
+ private static void createContents() {
+ // Create a Dynamic Table
+ tblDyn = new DynamicTable(shell, SWT.BORDER | SWT.FULL_SELECTION);
+ tblDyn.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ tblDyn.setHeaderVisible(true);
+ tblDyn.setLinesVisible(true);
+ {
+ tblcId = new DynamicTableColumn(tblDyn, SWT.NONE);
+ tblcId.setText("Id");
+ tblcId.setWidth("25px");
+
+ tblcFirstName = new DynamicTableColumn(tblDyn, SWT.NONE);
+ tblcFirstName.setText("First Name");
+ tblcFirstName.setWidth("50%", "100px");
+
+ tblcLastName = new DynamicTableColumn(tblDyn, SWT.NONE);
+ tblcLastName.setText("Last Name");
+ tblcLastName.setWidth("50%", "100px");
+
+ tblcAge = new DynamicTableColumn(tblDyn, SWT.NONE);
+ tblcAge.setText("Age");
+ tblcAge.setWidth("60px");
+ }
+
+ pnlButtons = new Composite(shell, SWT.NONE);
+ pnlButtons.setLayout(new GridLayout(1, false));
+ pnlButtons.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true, 1, 1));
+ {
+ btnAdd = new Button(pnlButtons, SWT.NONE);
+ btnAdd.setText("Add");
+ btnAdd.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ final TableItem tbli = new TableItem(tblDyn, SWT.NONE);
+ tbli.setText(0, Integer.toString(idCount++));
+ tbli.setText(1, firstNameSet[new Random().nextInt(4)]);
+ tbli.setText(2, lastNameSet[new Random().nextInt(4)]);
+ tbli.setText(3, birthDateSet[new Random().nextInt(4)]);
+ tblDyn.layout();
+ }
+ });
+ }
+ }
+
+ /**
+ * Create person
+ *
+ * @param i int
+ */
+ private static void createPerson(final int i) {
+ final TableItem tbli = new TableItem(tblDyn, SWT.NONE);
+ tbli.setText(0, Integer.toString(idCount++));
+ tbli.setText(1, firstNameSet[i]);
+ tbli.setText(2, lastNameSet[i]);
+ tbli.setText(3, birthDateSet[i]);
+ }
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/gradientComposite/SnippetGradientComposite.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/gradientComposite/SnippetGradientComposite.java
new file mode 100644
index 0000000..266809c
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/gradientComposite/SnippetGradientComposite.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * 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.gradientComposite;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * This snippet demonstrates the gradient composite
+ *
+ */
+public class SnippetGradientComposite {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setBackgroundMode(SWT.INHERIT_DEFAULT);
+ final FillLayout layout1 = new FillLayout(SWT.VERTICAL);
+ layout1.marginWidth = layout1.marginHeight = 10;
+ shell.setLayout(layout1);
+
+ // Displays the composite
+ final GradientComposite composite = new GradientComposite(shell, SWT.NONE);
+ composite.setGradientEnd(display.getSystemColor(SWT.COLOR_WHITE));
+ composite.setGradientStart(display.getSystemColor(SWT.COLOR_DARK_RED));
+
+ // And the content
+ final RowLayout layout2 = new RowLayout(SWT.VERTICAL);
+ layout2.marginWidth = layout2.marginHeight = layout2.spacing = 10;
+ composite.setLayout(layout2);
+ for (int i = 0; i < 8; i++) {
+ final Button button = new Button(composite, SWT.RADIO);
+ button.setForeground(display.getSystemColor(SWT.COLOR_RED));
+ button.setText("Button " + i);
+ }
+
+ // Open the shell
+ shell.setSize(640, 360);
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/header/HeaderSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/header/HeaderSnippet.java
new file mode 100644
index 0000000..d3f81eb
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/header/HeaderSnippet.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * 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.header;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the Header widget
+ *
+ */
+public class HeaderSnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(1, false));
+
+ final Image icon = new Image(display, HeaderSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/header/configure.png"));
+
+ shell.setText("Header Snippet");
+ shell.setLayout(new GridLayout(2, false));
+
+ final Header header = new Header(shell, SWT.NONE);
+ header.setTitle("Header title");
+ header.setImage(icon);
+ header.setDescription("Description area for the header. You can put all <b>additional</b>, <i>relevant information</i> to the description panel (or <u>jokes</u>, citations, ... what you want !)");
+ header.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false, 2, 1));
+
+ createRow(shell, "First Name");
+ createRow(shell, "Last Name");
+ createRow(shell, "E-mail");
+ createRow(shell, "Phone number");
+
+ shell.setSize(640, 350);
+ SWTGraphicUtil.centerShell(shell);
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ icon.dispose();
+ display.dispose();
+ }
+
+ private static void createRow(final Shell shell, final String label) {
+ final Label lbl = new Label(shell, SWT.NONE);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));
+
+ final Text text = new Text(shell, SWT.SINGLE | SWT.BORDER);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/header/configure.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/header/configure.png
new file mode 100644
index 0000000..ac159cc
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/header/configure.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/heapManager/HeapManagerSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/heapManager/HeapManagerSnippet.java
new file mode 100644
index 0000000..c02767d
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/heapManager/HeapManagerSnippet.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * 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)
+ *******************************************************************************/
+package org.mihalis.opal.heapManager;
+
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A simple snippet for the TextAssist Widget
+ */
+public class HeapManagerSnippet {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout());
+
+// new HeapManager(shell, SWT.NONE);
+
+ final int[] counter = new int[1];
+ counter[0] = 1;
+
+ display.timerExec(10, new Runnable() {
+
+ @Override
+ public void run() {
+ for (int i = 0; i < 10000; i++) {
+ @SuppressWarnings("unused")
+ final String[] temp = new String[1000];
+ }
+ counter[0]++;
+ if (counter[0] < 100) {
+ display.timerExec(10, this);
+ }
+ }
+ });
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/horizontalSpinner/HorizontalSpinnerSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/horizontalSpinner/HorizontalSpinnerSnippet.java
new file mode 100644
index 0000000..32ceb7d
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/horizontalSpinner/HorizontalSpinnerSnippet.java
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * 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.horizontalSpinner;
+
+import org.eclipse.swt.SWT;
+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.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.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Spinner;
+import org.eclipse.swt.widgets.ToolTip;
+
+/**
+ * A simple snipper for the Horizontal Spinner widget
+ *
+ */
+public class HorizontalSpinnerSnippet {
+
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(4, true));
+
+ createSpinnerGroup(shell);
+ createHorizontalSpinnerGroup(shell, "Default look", SWT.NONE);
+ createHorizontalSpinnerGroup(shell, "Buttons on the left", SWT.LEFT);
+ createHorizontalSpinnerGroup(shell, "Buttons on the right", SWT.RIGHT);
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+
+ }
+
+ private static void createSpinnerGroup(final Shell shell) {
+ final Group group = new Group(shell, SWT.NONE);
+ group.setLayout(new GridLayout(1, false));
+
+ final Label lbl1 = new Label(group, SWT.NONE);
+ lbl1.setText("Simple vertical spinner :");
+ final Spinner spinner1 = new Spinner(group, SWT.BORDER);
+ spinner1.setMinimum(0);
+ spinner1.setMaximum(1000);
+ spinner1.setSelection(500);
+ spinner1.setIncrement(1);
+ spinner1.setPageIncrement(100);
+
+ final Label lbl2 = new Label(group, SWT.NONE);
+ lbl2.setText("Floating point values in Spinner :");
+ final Spinner spinner2 = new Spinner(group, SWT.NONE);
+ // allow 3 decimal places
+ spinner2.setDigits(3);
+ // set the minimum value to 0.001
+ spinner2.setMinimum(1);
+ // set the maximum value to 20
+ spinner2.setMaximum(20000);
+ // set the increment value to 0.010
+ spinner2.setIncrement(10);
+ // set the seletion to 3.456
+ spinner2.setSelection(3456);
+ spinner2.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ final int selection = spinner2.getSelection();
+ final int digits = spinner2.getDigits();
+ System.out.println("Selection is " + selection / Math.pow(10, digits));
+ }
+ });
+
+ final Label lbl3 = new Label(group, SWT.NONE);
+ lbl3.setText("Validate input in a spinner widget :");
+ final Spinner spinner3 = new Spinner(group, SWT.BORDER);
+ spinner3.setValues(0, -100, 100, 0, 1, 10);
+ spinner3.setLayoutData(new GridData(200, SWT.DEFAULT));
+ final ToolTip toolTip = new ToolTip(shell, SWT.BALLOON | SWT.ICON_WARNING);
+ spinner3.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(final ModifyEvent e) {
+ final String string = spinner3.getText();
+ String message = null;
+ try {
+ final int value = Integer.parseInt(string);
+ final int maximum = spinner3.getMaximum();
+ final int minimum = spinner3.getMinimum();
+ if (value > maximum) {
+ message = "Current input is greater than the maximum limit (" + maximum + ")";
+ } else if (value < minimum) {
+ message = "Current input is less than the minimum limit (" + minimum + ")";
+ }
+ } catch (final Exception ex) { // NOSONAR
+ message = "Current input is not numeric";
+ }
+ if (message != null) {
+ spinner3.setForeground(shell.getDisplay().getSystemColor(SWT.COLOR_RED));
+ final Rectangle rect = spinner3.getBounds();
+ final GC gc = new GC(spinner3);
+ final Point pt = gc.textExtent(string);
+ gc.dispose();
+ toolTip.setLocation(shell.getDisplay().map(shell, null, rect.x + pt.x, rect.y + rect.height));
+ toolTip.setMessage(message);
+ toolTip.setVisible(true);
+ } else {
+ toolTip.setVisible(false);
+ spinner3.setForeground(null);
+ }
+ }
+ });
+
+ }
+
+ private static void createHorizontalSpinnerGroup(final Shell shell, final String title, final int style) {
+ final Group group = new Group(shell, SWT.NONE);
+ group.setLayout(new GridLayout(1, false));
+ group.setText(title);
+
+ final Label lbl1 = new Label(group, SWT.NONE);
+ lbl1.setText("Simple horizontal spinner :");
+ final HorizontalSpinner spinner1 = new HorizontalSpinner(group, SWT.BORDER | style);
+ spinner1.setMinimum(0);
+ spinner1.setMaximum(1000);
+ spinner1.setSelection(500);
+ spinner1.setIncrement(1);
+ spinner1.setPageIncrement(100);
+
+ final Label lbl2 = new Label(group, SWT.NONE);
+ lbl2.setText("Floating point values in Spinner :");
+ final HorizontalSpinner spinner2 = new HorizontalSpinner(group, style);
+ // allow 3 decimal places
+ spinner2.setDigits(3);
+ // set the minimum value to 0.001
+ spinner2.setMinimum(1);
+ // set the maximum value to 20
+ spinner2.setMaximum(20000);
+ // set the increment value to 0.010
+ spinner2.setIncrement(10);
+ // set the seletion to 3.456
+ spinner2.setSelection(3456);
+ spinner2.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ final int selection = spinner2.getSelection();
+ final int digits = spinner2.getDigits();
+ System.out.println("Selection is " + selection / Math.pow(10, digits));
+ }
+ });
+
+ final Label lbl3 = new Label(group, SWT.NONE);
+ lbl3.setText("Validate input in a spinner widget :");
+ final HorizontalSpinner spinner3 = new HorizontalSpinner(group, SWT.BORDER | style);
+ spinner3.setValues(0, -100, 100, 0, 1, 10);
+ spinner3.setLayoutData(new GridData(200, SWT.DEFAULT));
+ final ToolTip toolTip = new ToolTip(shell, SWT.BALLOON | SWT.ICON_WARNING);
+ spinner3.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(final ModifyEvent e) {
+ final String string = spinner3.getText();
+ String message = null;
+ try {
+ final int value = Integer.parseInt(string);
+ final int maximum = spinner3.getMaximum();
+ final int minimum = spinner3.getMinimum();
+ if (value > maximum) {
+ message = "Current input is greater than the maximum limit (" + maximum + ")";
+ } else if (value < minimum) {
+ message = "Current input is less than the minimum limit (" + minimum + ")";
+ }
+ } catch (final Exception ex) { // NOSONAR
+ message = "Current input is not numeric";
+ }
+ if (message != null) {
+ spinner3.setForeground(shell.getDisplay().getSystemColor(SWT.COLOR_RED));
+ final Rectangle rect = spinner3.getBounds();
+ final GC gc = new GC(spinner3);
+ final Point pt = gc.textExtent(string);
+ gc.dispose();
+ toolTip.setLocation(shell.getDisplay().map(group, null, rect.x + pt.x, rect.y + rect.height));
+ toolTip.setMessage(message);
+ toolTip.setVisible(true);
+ } else {
+ toolTip.setVisible(false);
+ spinner3.setForeground(null);
+ }
+ }
+ });
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/ImageSelectorSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/ImageSelectorSnippet.java
new file mode 100644
index 0000000..776aaf0
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/ImageSelectorSnippet.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * 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.imageSelector;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A simple snipper for the Image Selector widget
+ *
+ */
+public class ImageSelectorSnippet {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout());
+
+ // Create the list of images
+ final List<ISItem> items = new LinkedList<ISItem>();
+ items.add(new ISItem("Black Eyed Peas", "org/mihalis/opal/imageSelector/images/Black Eyed Peas.jpg"));
+ items.add(new ISItem("Coldplay", "org/mihalis/opal/imageSelector/images/Coldplay.jpg"));
+ items.add(new ISItem("Foo Fighters", "org/mihalis/opal/imageSelector/images/Foo Fighters.jpg"));
+ items.add(new ISItem("Gorillaz", "org/mihalis/opal/imageSelector/images/Gorillaz.jpg"));
+ items.add(new ISItem("Green Day", "org/mihalis/opal/imageSelector/images/Green Day.jpg"));
+ items.add(new ISItem("Moby", "org/mihalis/opal/imageSelector/images/Moby.jpg"));
+ items.add(new ISItem("Norah Jones", "org/mihalis/opal/imageSelector/images/Norah Jones.jpg"));
+ items.add(new ISItem("Shivaree", "org/mihalis/opal/imageSelector/images/Shivaree.jpg"));
+ items.add(new ISItem("Sin City", "org/mihalis/opal/imageSelector/images/Sin City.jpg"));
+
+ final ImageSelector imageSelector = new ImageSelector(shell, SWT.NONE);
+ imageSelector.setItems(items);
+
+ // Open the shell
+ shell.setSize(640, 360);
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Black Eyed Peas.jpg b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Black Eyed Peas.jpg
new file mode 100644
index 0000000..127cb25
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Black Eyed Peas.jpg
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Coldplay.jpg b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Coldplay.jpg
new file mode 100644
index 0000000..2ff7d89
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Coldplay.jpg
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Foo Fighters.jpg b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Foo Fighters.jpg
new file mode 100644
index 0000000..7218439
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Foo Fighters.jpg
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Gorillaz.jpg b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Gorillaz.jpg
new file mode 100644
index 0000000..a0193f7
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Gorillaz.jpg
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Green Day.jpg b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Green Day.jpg
new file mode 100644
index 0000000..994beb4
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Green Day.jpg
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Moby.jpg b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Moby.jpg
new file mode 100644
index 0000000..ef6847e
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Moby.jpg
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Norah Jones.jpg b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Norah Jones.jpg
new file mode 100644
index 0000000..de2fcbc
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Norah Jones.jpg
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Shivaree.jpg b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Shivaree.jpg
new file mode 100644
index 0000000..fa87702
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Shivaree.jpg
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Sin City.jpg b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Sin City.jpg
new file mode 100644
index 0000000..98dc643
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/images/Sin City.jpg
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/infinitePanel/SnippetInfiniteProgressPanel.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/infinitePanel/SnippetInfiniteProgressPanel.java
new file mode 100644
index 0000000..397cd0c
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/infinitePanel/SnippetInfiniteProgressPanel.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * 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.infinitePanel;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+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.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * This snippet demonstrates the infinite progress panel
+ *
+ */
+public class SnippetInfiniteProgressPanel {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell();
+ shell.setLayout(new GridLayout(2, false));
+
+ createRow(shell, "First Name");
+ createRow(shell, "Last Name");
+ createRow(shell, "E-mail");
+ createRow(shell, "Phone number");
+
+ createButtons(shell);
+
+ shell.setSize(shell.computeSize(400, 400));
+
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+ private static void createRow(final Shell shell, final String label) {
+ final Label lbl = new Label(shell, SWT.NONE);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));
+
+ final Text text = new Text(shell, SWT.SINGLE | SWT.BORDER);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ }
+
+ private static void createButtons(final Shell shell) {
+ final Composite composite = new Composite(shell, SWT.NONE);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+ composite.setLayout(new GridLayout(2, false));
+
+ final Button ok = new Button(composite, SWT.PUSH);
+ ok.setText("Ok");
+ ok.setLayoutData(new GridData(SWT.END, SWT.END, true, true));
+ ok.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ // Retrieve an infinite progress panel
+ final InfiniteProgressPanel panel = InfiniteProgressPanel.getInfiniteProgressPanelFor(shell);
+
+ // Set up a text (optional)
+ panel.setText("Please wait...");
+ panel.setTextColor(shell.getDisplay().getSystemColor(SWT.COLOR_DARK_RED));
+ panel.setTextFont(new Font(shell.getDisplay(), "Lucida Sans", 18, SWT.BOLD));
+
+ panel.start();
+ final Thread performer = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ performLongTask(panel);
+ }
+ }, "Performer");
+ performer.start();
+ }
+
+ private void performLongTask(final InfiniteProgressPanel panel) {
+ try {
+ Thread.sleep(4000);
+ } catch (final InterruptedException e) {
+ e.printStackTrace(); // NOSONAR
+ }
+ // Stop the progress panel
+ panel.stop();
+ }
+
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ }
+ });
+
+ final Button cancel = new Button(composite, SWT.PUSH);
+ cancel.setText("Cancel");
+ cancel.setLayoutData(new GridData(SWT.CENTER, SWT.END, false, true));
+ cancel.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ shell.dispose();
+ }
+
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ shell.dispose();
+ }
+ });
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/DualListSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/DualListSnippet.java
new file mode 100644
index 0000000..2166fe3
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/DualListSnippet.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * 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.itemSelector;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.itemSelector.DLItem.LAST_ACTION;
+
+/**
+ * A simple snipper for the ItemSelector Widget
+ *
+ */
+public class DualListSnippet {
+
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("Dual List Snippet");
+ shell.setSize(600, 600);
+ shell.setLayout(new GridLayout(1, false));
+
+ final DualList dl = new DualList(shell, SWT.NONE);
+ dl.setItems(createItems(shell));
+
+ dl.addSelectionChangeListener(new SelectionChangeListener() {
+
+ @Override
+ public void widgetSelected(final SelectionChangeEvent e) {
+ System.out.println("Selection Change Listener called");
+ for (final DLItem item : e.getItems()) {
+ final StringBuilder sb = new StringBuilder();
+ if (item.getLastAction() == LAST_ACTION.SELECTION) {
+ sb.append("[SELECTION] ");
+ } else {
+ sb.append("[DE-SELECTION] ");
+ }
+ sb.append(item.getText());
+ System.out.println(sb.toString());
+ }
+ }
+ });
+
+ dl.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+
+ }
+
+ private static List<DLItem> createItems(final Shell shell) {
+ final List<DLItem> list = new ArrayList<DLItem>();
+
+ String defaultFontName = null;
+ int defaultHeight = -1;
+ for (final FontData fontData : shell.getFont().getFontData()) {
+ if (defaultFontName == null) {
+ defaultFontName = fontData.getName();
+ }
+ if (defaultHeight == -1) {
+ defaultHeight = fontData.getHeight();
+ }
+ }
+
+ final Font font = new Font(shell.getDisplay(), defaultFontName, defaultHeight, SWT.BOLD);
+
+ list.add(new DLItem("Austria", createImage(shell, "austria")));
+ list.add(new DLItem("Belgium", createImage(shell, "belgium")));
+ list.add(new DLItem("Bulgaria", createImage(shell, "bulgaria")));
+ list.add(new DLItem("Cyprus", createImage(shell, "cyprus")));
+ list.add(new DLItem("Czech Republic", createImage(shell, "czech")));
+ list.add(new DLItem("Denmark", createImage(shell, "denmark")));
+ list.add(new DLItem("Estonia", createImage(shell, "estonia")));
+ list.add(new DLItem("Finland", createImage(shell, "finland")));
+ list.add(new DLItem("France", createImage(shell, "france"), font));
+ list.add(new DLItem("Germany", createImage(shell, "germany")));
+ list.add(new DLItem("Greece", createImage(shell, "greece")));
+ list.add(new DLItem("Hungary", createImage(shell, "hungary")));
+ list.add(new DLItem("Ireland", createImage(shell, "ireland")));
+ list.add(new DLItem("Italy", createImage(shell, "italy")));
+ list.add(new DLItem("Latvia", createImage(shell, "latvia")));
+ list.add(new DLItem("Lithuania", createImage(shell, "lithuania")));
+ list.add(new DLItem("Luxembourg", createImage(shell, "luxembourg")));
+ list.add(new DLItem("Malta", createImage(shell, "malta")));
+ list.add(new DLItem("Netherlands", createImage(shell, "netherlands")));
+ list.add(new DLItem("Poland", createImage(shell, "poland"), shell.getDisplay().getSystemColor(SWT.COLOR_WHITE), shell.getDisplay().getSystemColor(SWT.COLOR_RED)));
+ list.add(new DLItem("Portugal", createImage(shell, "portugal")));
+ list.add(new DLItem("Romania", createImage(shell, "romania")));
+ list.add(new DLItem("Slovakia", createImage(shell, "slovakia")));
+ list.add(new DLItem("Slovenia", createImage(shell, "slovenia")));
+ list.add(new DLItem("Spain", createImage(shell, "spain")));
+ list.add(new DLItem("Sweden", createImage(shell, "sweden")));
+ list.add(new DLItem("United Kingdom", createImage(shell, "unitedkingdom")));
+
+ shell.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ font.dispose();
+ }
+ });
+
+ return list;
+ }
+
+ private static Image createImage(final Shell shell, final String fileName) {
+ final Image image = new Image(shell.getDisplay(), DualListSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/itemSelector/flags/" + fileName + ".png"));
+ shell.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent de) {
+ image.dispose();
+ }
+ });
+ return image;
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/DualListTextSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/DualListTextSnippet.java
new file mode 100644
index 0000000..5fa8638
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/DualListTextSnippet.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * 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.itemSelector;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+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.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A simple snipper for the ItemSelector Widget
+ *
+ */
+public class DualListTextSnippet {
+
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("Dual List Snippet");
+ shell.setSize(600, 600);
+ shell.setLayout(new GridLayout(1, false));
+
+ final DualList dl = new DualList(shell, SWT.NONE);
+ dl.setItems(createItems(shell));
+ dl.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ System.out.println("Selection Listener called");
+
+ }
+
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+
+ }
+ });
+
+ dl.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+
+ }
+
+ private static List<DLItem> createItems(final Shell shell) {
+ final List<DLItem> list = new ArrayList<DLItem>();
+
+ String defaultFontName = null;
+ int defaultHeight = -1;
+ for (final FontData fontData : shell.getFont().getFontData()) {
+ if (defaultFontName == null) {
+ defaultFontName = fontData.getName();
+ }
+ if (defaultHeight == -1) {
+ defaultHeight = fontData.getHeight();
+ }
+ }
+
+ final Font font = new Font(shell.getDisplay(), defaultFontName, defaultHeight, SWT.BOLD);
+
+ list.add(new DLItem("Austria"));
+ list.add(new DLItem("Belgium"));
+ list.add(new DLItem("Bulgaria"));
+ list.add(new DLItem("Cyprus"));
+ list.add(new DLItem("Czech Republic"));
+ list.add(new DLItem("Denmark"));
+ list.add(new DLItem("Estonia"));
+ list.add(new DLItem("Finland"));
+ list.add(new DLItem("France"));
+ list.add(new DLItem("Germany"));
+ list.add(new DLItem("Greece"));
+ list.add(new DLItem("Hungary"));
+ list.add(new DLItem("Ireland"));
+ list.add(new DLItem("Italy"));
+ list.add(new DLItem("Latvia"));
+ list.add(new DLItem("Lithuania"));
+ list.add(new DLItem("Luxembourg"));
+ list.add(new DLItem("Malta"));
+ list.add(new DLItem("Netherlands"));
+ list.add(new DLItem("Poland"));
+ list.add(new DLItem("Portugal"));
+ list.add(new DLItem("Romania"));
+ list.add(new DLItem("Slovakia"));
+ list.add(new DLItem("Slovenia"));
+ list.add(new DLItem("Spain"));
+ list.add(new DLItem("Sweden"));
+ list.add(new DLItem("United Kingdom"));
+
+ shell.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ font.dispose();
+ }
+ });
+
+ return list;
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/austria.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/austria.png
new file mode 100644
index 0000000..2805d55
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/austria.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/belgium.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/belgium.png
new file mode 100644
index 0000000..5a750ac
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/belgium.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/bulgaria.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/bulgaria.png
new file mode 100644
index 0000000..1ca998d
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/bulgaria.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/cyprus.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/cyprus.png
new file mode 100644
index 0000000..e831ff9
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/cyprus.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/czech.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/czech.png
new file mode 100644
index 0000000..af29812
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/czech.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/denmark.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/denmark.png
new file mode 100644
index 0000000..f7ed409
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/denmark.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/estonia.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/estonia.png
new file mode 100644
index 0000000..77d5ef4
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/estonia.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/finland.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/finland.png
new file mode 100644
index 0000000..c8cd203
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/finland.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/france.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/france.png
new file mode 100644
index 0000000..a6ae6e6
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/france.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/germany.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/germany.png
new file mode 100644
index 0000000..fdcea4f
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/germany.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/greece.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/greece.png
new file mode 100644
index 0000000..eff880c
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/greece.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/hungary.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/hungary.png
new file mode 100644
index 0000000..e784188
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/hungary.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/ireland.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/ireland.png
new file mode 100644
index 0000000..e25a8a2
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/ireland.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/italy.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/italy.png
new file mode 100644
index 0000000..509d8a1
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/italy.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/latvia.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/latvia.png
new file mode 100644
index 0000000..43d4425
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/latvia.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/lithuania.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/lithuania.png
new file mode 100644
index 0000000..93f62bc
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/lithuania.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/luxembourg.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/luxembourg.png
new file mode 100644
index 0000000..5c6c332
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/luxembourg.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/malta.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/malta.png
new file mode 100644
index 0000000..fcb79d6
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/malta.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/netherlands.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/netherlands.png
new file mode 100644
index 0000000..b927541
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/netherlands.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/poland.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/poland.png
new file mode 100644
index 0000000..a30ee1a
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/poland.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/portugal.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/portugal.png
new file mode 100644
index 0000000..28c4fff
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/portugal.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/romania.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/romania.png
new file mode 100644
index 0000000..05f56ee
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/romania.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/slovakia.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/slovakia.png
new file mode 100644
index 0000000..7d015dd
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/slovakia.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/slovenia.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/slovenia.png
new file mode 100644
index 0000000..7dc76fc
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/slovenia.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/spain.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/spain.png
new file mode 100644
index 0000000..c11275e
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/spain.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/sweden.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/sweden.png
new file mode 100644
index 0000000..27a260a
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/sweden.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/unitedkingdom.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/unitedkingdom.png
new file mode 100644
index 0000000..5a58613
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/itemSelector/flags/unitedkingdom.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/LauncherSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/LauncherSnippet.java
new file mode 100644
index 0000000..e98deae
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/LauncherSnippet.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * 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.launcher;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.opalDialog.Dialog;
+
+/**
+ * A simple snippet for the Launcher Widget
+ *
+ */
+public class LauncherSnippet {
+
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(1, false));
+
+ final Label title = new Label(shell, SWT.NONE);
+ title.setText("Launcher");
+ title.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+
+ final Launcher l = new Launcher(shell, SWT.NONE);
+ l.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+ l.addItem("Address Book", "org/mihalis/opal/launcher/icons/x-office-address-book.png");
+ l.addItem("Calendar", "org/mihalis/opal/launcher/icons/x-office-calendar.png");
+ l.addItem("Presentation", "org/mihalis/opal/launcher/icons/x-office-presentation.png");
+ l.addItem("Spreadsheet", "org/mihalis/opal/launcher/icons/x-office-spreadsheet.png");
+
+ l.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ Dialog.inform("Selection", "You have selected item #" + l.getSelection());
+ }
+
+ });
+
+ final Label under = new Label(shell, SWT.NONE);
+ under.setText("Double-click an icon to launch the program");
+ under.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+
+ shell.setSize(new Point(436, 546));
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-address-book.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-address-book.png
new file mode 100644
index 0000000..eb3b9b4
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-address-book.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-calendar.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-calendar.png
new file mode 100644
index 0000000..ca34b65
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-calendar.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-presentation.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-presentation.png
new file mode 100644
index 0000000..9d62d4d
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-presentation.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-spreadsheet.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-spreadsheet.png
new file mode 100644
index 0000000..d83da92
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/launcher/icons/x-office-spreadsheet.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/login/LoginDialogSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/login/LoginDialogSnippet.java
new file mode 100644
index 0000000..0b47748
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/login/LoginDialogSnippet.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 API and implementation
+ *******************************************************************************/
+package org.mihalis.opal.login;
+
+import java.util.Locale;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+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.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the Login Dialog widget
+ *
+ */
+public class LoginDialogSnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+
+ Locale.setDefault(Locale.ENGLISH);
+
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("Login dialog snippet");
+ shell.setLayout(new GridLayout(2, false));
+
+ // Basic Login dialog
+ final Label label1 = new Label(shell, SWT.WRAP);
+ label1.setText("This is the basic dialog box, \nwithout any customization");
+ label1.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+
+ final Button button1 = new Button(shell, SWT.PUSH);
+ button1.setText("Open basic dialog");
+ button1.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false));
+
+ final LoginDialogVerifier verifier = new LoginDialogVerifier() {
+
+ @Override
+ public void authenticate(final String login, final String password) throws Exception {
+ if ("".equals(login)) {
+ throw new Exception("Please enter a login.");
+ }
+
+ if ("".equals(password)) {
+ throw new Exception("Please enter a password.");
+ }
+
+ if (!login.equalsIgnoreCase("laurent")) {
+ throw new Exception("Login unknown.");
+ }
+
+ if (!password.equalsIgnoreCase("laurent")) {
+ throw new Exception("Authentication failed, please check your password.");
+ }
+
+ }
+ };
+
+ button1.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+
+ final LoginDialog dialog = new LoginDialog();
+ dialog.setVerifier(verifier);
+
+ final boolean result = dialog.open();
+ if (result) {
+ System.out.println("Login confirmed : " + dialog.getLogin());
+ } else {
+ System.out.println("User canceled !");
+ }
+ }
+ });
+
+ final Label separator = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
+ separator.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 2, 1));
+
+ // Login dialog with image, description, default login, and no button
+ // "remember my password"
+ final Label label2 = new Label(shell, SWT.NONE);
+ label2.setText("This is a customized login (image, description, \ndefault login, multiple login values, \nno button 'remember my password'");
+ label2.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+
+ final Button button2 = new Button(shell, SWT.PUSH);
+ button2.setText("Open customized dialog");
+ button2.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+
+ button2.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+
+ final LoginDialog dialog = new LoginDialog();
+ dialog.setImage(new Image(display, LoginDialogSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/login/image.png")));
+ dialog.setDescription("Please login to our system...\nPlease remember that the password is the same as the login :)");
+ dialog.setAutorizedLogin("Laurent", "Albert", "Erik", "Ulrich", "Luis");
+ dialog.setLogin("Laurent");
+ dialog.setDisplayRememberPassword(false);
+ dialog.setVerifier(verifier);
+
+ final boolean result = dialog.open();
+ if (result) {
+ System.out.println("Login confirmed : " + dialog.getLogin());
+ } else {
+ System.out.println("User canceled !");
+ }
+ }
+ });
+
+ shell.pack();
+ shell.open();
+ SWTGraphicUtil.centerShell(shell);
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/login/image.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/login/image.png
new file mode 100644
index 0000000..74fbf3c
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/login/image.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/multiChoice/Country.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/multiChoice/Country.java
new file mode 100644
index 0000000..55ba3b8
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/multiChoice/Country.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * 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.multiChoice;
+
+/**
+ * This is a POJO that represents a country
+ */
+public class Country {
+ private String name;
+ private int population;
+ private String code;
+
+ public Country(final String name, final int population) {
+ this.name = name;
+ this.population = population;
+ }
+
+ public Country(final String name, final String code) {
+ this.name = name;
+ this.code = code;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public int getPopulation() {
+ return this.population;
+ }
+
+ public void setPopulation(final int population) {
+ this.population = population;
+ }
+
+ /**
+ * @return the code
+ */
+ public String getCode() {
+ return this.code;
+ }
+
+ /**
+ * @param code the code to set
+ */
+ public void setCode(final String code) {
+ this.code = code;
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (this.code == null ? 0 : this.code.hashCode());
+ result = prime * result + (this.name == null ? 0 : this.name.hashCode());
+ result = prime * result + this.population;
+ return result;
+ }
+
+ /**
+ * @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 Country other = (Country) obj;
+ if (this.code == null) {
+ if (other.code != null) {
+ return false;
+ }
+ } else if (!this.code.equals(other.code)) {
+ return false;
+ }
+ if (this.name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!this.name.equals(other.name)) {
+ return false;
+ }
+ if (this.population != other.population) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return this.name;
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/multiChoice/MultiChoiceSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/multiChoice/MultiChoiceSnippet.java
new file mode 100644
index 0000000..ef41563
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/multiChoice/MultiChoiceSnippet.java
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ * 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)
+ *******************************************************************************/
+package org.mihalis.opal.multiChoice;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.utils.SimpleSelectionAdapter;
+
+/**
+ * A simple snippet for the MultiChoice Widget
+ */
+public class MultiChoiceSnippet {
+
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(4, false));
+ shell.setText("MultiChoice Example");
+
+ // Data
+ final String[] euroZone = new String[] { "Austria", "Belgium", "Cyprus", "Estonia", "Finland", "France", "Germany", "Greece", "Ireland", "Italy", "Luxembourg", "Malta", "Netherlands", "Portugal", "Slovakia", "Slovenia", "Spain" };
+
+ final List<Country> membersOfEuropeanUnion = new ArrayList<Country>();
+ membersOfEuropeanUnion.add(new Country("Austria", 8372930));
+ membersOfEuropeanUnion.add(new Country("Belgium", 10827519));
+ membersOfEuropeanUnion.add(new Country("Bulgaria", 7576751));
+ membersOfEuropeanUnion.add(new Country("Cyprus", 801851));
+ membersOfEuropeanUnion.add(new Country("Czech Republic", 10512397));
+ membersOfEuropeanUnion.add(new Country("Denmark", 5547088));
+ membersOfEuropeanUnion.add(new Country("Estonia", 1340274));
+ membersOfEuropeanUnion.add(new Country("Finland", 5530575));
+ membersOfEuropeanUnion.add(new Country("France", 64709480));
+ membersOfEuropeanUnion.add(new Country("Germany", 81757595));
+ membersOfEuropeanUnion.add(new Country("Greece", 11125179));
+ membersOfEuropeanUnion.add(new Country("Hungary", 10013628));
+ membersOfEuropeanUnion.add(new Country("Ireland", 4450878));
+ membersOfEuropeanUnion.add(new Country("Italy", 60397353));
+ membersOfEuropeanUnion.add(new Country("Latvia", 2248961));
+ membersOfEuropeanUnion.add(new Country("Lithuania", 3329227));
+ membersOfEuropeanUnion.add(new Country("Luxembourg", 502207));
+ membersOfEuropeanUnion.add(new Country("Malta", 416333));
+ membersOfEuropeanUnion.add(new Country("Netherlands", 16576800));
+ membersOfEuropeanUnion.add(new Country("Poland", 38163895));
+ membersOfEuropeanUnion.add(new Country("Portugal", 11317192));
+ membersOfEuropeanUnion.add(new Country("Romania", 21466174));
+ membersOfEuropeanUnion.add(new Country("Slovakia", 5424057));
+ membersOfEuropeanUnion.add(new Country("Slovenia", 2054119));
+ membersOfEuropeanUnion.add(new Country("Spain", 46087170));
+ membersOfEuropeanUnion.add(new Country("Sweden", 9347899));
+ membersOfEuropeanUnion.add(new Country("United Kingdom", 62041708));
+
+ final List<Country> membersOfEUSelectAll = new ArrayList<Country>();
+ membersOfEUSelectAll.addAll(membersOfEuropeanUnion);
+ membersOfEUSelectAll.add(new Country("Select All", -1));
+
+ final List<Country> countryCodes = new ArrayList<Country>();
+ countryCodes.add(new Country("France", "FR"));
+ countryCodes.add(new Country("United states", "US"));
+ countryCodes.add(new Country("United Kingdom", "UK"));
+ countryCodes.add(new Country("Germany", "DE"));
+ countryCodes.add(new Country("Belgium", "BE"));
+ countryCodes.add(new Country("Netherland", "NL"));
+ countryCodes.add(new Country("Italy", "IT"));
+ countryCodes.add(new Country("Spain", "ES"));
+ countryCodes.add(new Country("Portugal", "PT"));
+
+ // Draw the window
+ drawLabel(shell, "Simple Multichoice :");
+ final MultiChoice<String> mcSimple = new MultiChoice<String>(shell, SWT.READ_ONLY);
+ final GridData gridData = new GridData(GridData.FILL, GridData.BEGINNING, true, true);
+ gridData.widthHint = 200;
+ mcSimple.setLayoutData(gridData);
+ mcSimple.addAll(euroZone);
+ addButons(mcSimple);
+
+ drawLabel(shell, "Multichoice with beans :");
+ final MultiChoice<Country> mcBeans = new MultiChoice<Country>(shell, SWT.READ_ONLY);
+ mcBeans.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, true));
+ mcBeans.addAll(membersOfEuropeanUnion);
+ addButons(mcBeans);
+
+ drawLabel(shell, "Selection listener :");
+ final MultiChoice<Country> mcSL = new MultiChoice<Country>(shell, SWT.READ_ONLY);
+ mcSL.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, true));
+ mcSL.setSelectionListener(new MultiChoiceSelectionListener<Country>(mcSL) {
+
+ @Override
+ public void handle(final MultiChoice<Country> parent, final Country receiver, final boolean selection, final Shell popup) {
+ if ("Select All".equals(receiver.toString())) {
+ if (selection) {
+ parent.deselectAll();
+ parent.selectAll();
+ } else {
+ parent.deselectAll();
+ }
+ popup.setVisible(false);
+ }
+
+ }
+ });
+ mcSL.addAll(membersOfEUSelectAll);
+ addButons(mcSL);
+
+ drawLabel(shell, "3 columns :");
+ final MultiChoice<String> mc3Columns = new MultiChoice<String>(shell, SWT.READ_ONLY);
+ mc3Columns.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, true));
+ mc3Columns.addAll(euroZone);
+ mc3Columns.setNumberOfColumns(3);
+ addButons(mc3Columns);
+
+ drawLabel(shell, "Other separator :");
+ final MultiChoice<String> mcOtherSeparator = new MultiChoice<String>(shell, SWT.READ_ONLY);
+ mcOtherSeparator.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, true));
+ mcOtherSeparator.addAll(euroZone);
+ mcOtherSeparator.setSeparator(" - ");
+ addButons(mcOtherSeparator);
+
+ drawLabel(shell, "Modifiable combo :");
+ final MultiChoice<Country> mcModify = new MultiChoice<Country>(shell, SWT.NONE);
+ mcModify.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, true));
+ mcModify.setLabelProvider(new MultiChoiceLabelProvider() {
+ @Override
+ public String getText(final Object element) {
+ if (element == null || !(element instanceof Country)) {
+ return "";
+ }
+ return ((Country) element).getCode();
+ }
+ });
+ mcModify.addAll(countryCodes);
+ addButons(mcModify);
+
+ drawLabel(shell, "Lot of data :");
+ final List<String> data = new ArrayList<String>();
+ for (int i = 0; i < 1000; i++) {
+ data.add("Data #" + i);
+ }
+ final MultiChoice<String> mcLotOfData = new MultiChoice<String>(shell, SWT.NONE);
+ mcLotOfData.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, true));
+ mcLotOfData.setLabelProvider(new MultiChoiceLabelProvider() {
+ @Override
+ public String getText(final Object element) {
+ if (element == null) {
+ return "";
+ }
+ return (String) element;
+ }
+ });
+ mcLotOfData.addAll(data);
+ addButons(mcLotOfData);
+
+ // display the shell...
+ shell.open();
+ shell.pack();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+ private static void drawLabel(final Shell shell, final String text) {
+ final Label label = new Label(shell, SWT.NONE);
+ label.setText(text);
+ label.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false));
+ }
+
+ private static void addButons(final MultiChoice<?> mc) {
+ final Button buttonShowSelection = new Button(mc.getParent(), SWT.PUSH);
+ buttonShowSelection.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false));
+ buttonShowSelection.setText("Show selection");
+ buttonShowSelection.addSelectionListener(new SimpleSelectionAdapter() {
+
+ @Override
+ public void handle(final SelectionEvent e) {
+ final Iterator<?> it = mc.getSelection().iterator();
+ final StringBuilder sb = new StringBuilder();
+ while (it.hasNext()) {
+ sb.append(it.next().toString());
+ if (it.hasNext()) {
+ sb.append(", ");
+ }
+ }
+ final MessageBox mb = new MessageBox(mc.getShell(), SWT.OK);
+ mb.setMessage(sb.toString());
+ mb.open();
+ }
+ });
+
+ final Button buttonShowSelectedIndex = new Button(mc.getParent(), SWT.PUSH);
+ buttonShowSelectedIndex.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false));
+ buttonShowSelectedIndex.setText("Show selected index");
+ buttonShowSelectedIndex.addSelectionListener(new SimpleSelectionAdapter() {
+
+ @Override
+ public void handle(final SelectionEvent e) {
+ final StringBuilder sb = new StringBuilder();
+ final int[] selectedIndex = mc.getSelectedIndex();
+ if (selectedIndex.length > 0) {
+ sb.append(selectedIndex[0]);
+ for (int i = 1; i < selectedIndex.length; i++) {
+ sb.append(",");
+ sb.append(selectedIndex[i]);
+ }
+ } else {
+ sb.append("Empty");
+ }
+ final MessageBox mb = new MessageBox(mc.getShell(), SWT.OK);
+ mb.setMessage(sb.toString());
+ mb.open();
+ }
+ });
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/notify/NotifierSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/notify/NotifierSnippet.java
new file mode 100644
index 0000000..206dd6f
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/notify/NotifierSnippet.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * 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.notify;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.notify.NotifierColorsFactory.NotifierTheme;
+
+/**
+ * This snippet demonstrates the notifier widget
+ *
+ */
+public class NotifierSnippet {
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("Notifier Snippet");
+ shell.setSize(200, 200);
+ shell.setLayout(new FillLayout(SWT.VERTICAL));
+
+ final int[] counter = new int[1];
+ counter[0] = 0;
+
+ // Yellow theme (default)
+ final Button testerYellow = new Button(shell, SWT.PUSH);
+ testerYellow.setText("Push me [Yellow theme]!");
+ testerYellow.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ Notifier.notify("New Mail message", "Laurent CARON (lcaron@...)<br/><br/>Test message #" + counter[0] + "...");
+ counter[0]++;
+ }
+
+ });
+
+ // Blue theme
+ final Button testerBlue = new Button(shell, SWT.PUSH);
+ testerBlue.setText("Push me [Blue theme]!");
+ testerBlue.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ Notifier.notify("New Mail message", "Laurent CARON (lcaron@...)<br/><br/>Test message #" + counter[0] + "...", NotifierTheme.BLUE_THEME);
+ counter[0]++;
+ }
+
+ });
+
+ // Grey theme
+ final Button testerGrey = new Button(shell, SWT.PUSH);
+ testerGrey.setText("Push me [Gray theme]!");
+ testerGrey.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ Notifier.notify("New Mail message", "Laurent CARON (lcaron@...)<br/><br/>Test message #" + counter[0] + "...", NotifierTheme.GRAY_THEME);
+ counter[0]++;
+ }
+
+ });
+
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/obutton/OButtonSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/obutton/OButtonSnippet.java
new file mode 100644
index 0000000..a7aaf98
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/obutton/OButtonSnippet.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * 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.obutton;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Snippet for the OButton widget
+ */
+public class OButtonSnippet {
+ private static Shell shell;
+ private static Image icon;
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ shell = new Shell(display);
+ shell.setText("OButton Snippet");
+ shell.setLayout(new GridLayout(10, false));
+
+ icon = new Image(display, OButtonSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/obutton/user.png"));
+
+ createButtons(DefaultButtonRenderer.getInstance(), "Defaut theme:");
+ createButtons(RedButtonRenderer.getInstance(), "Red theme:");
+ createButtons(GreenButtonRenderer.getInstance(), "Green theme:");
+ createButtons(OrangeButtonRenderer.getInstance(), "Orange theme:");
+ createButtons(PurpleButtonRenderer.getInstance(), "Purple theme:");
+
+ shell.pack();
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ icon.dispose();
+ display.dispose();
+
+ }
+
+ private static void createButtons(final ButtonRenderer renderer, final String text) {
+ final Label label = new Label(shell, SWT.NONE);
+ label.setText(text);
+ label.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ final OButton button1 = new OButton(shell, SWT.PUSH);
+ button1.setText("Normal button");
+ final GridData gd = new GridData(GridData.BEGINNING, GridData.CENTER, false, false);
+ gd.widthHint = 200;
+ button1.setLayoutData(gd);
+ button1.setButtonRenderer(renderer);
+
+ final OButton button2 = new OButton(shell, SWT.PUSH);
+ button2.setText("Text & image");
+ button2.setImage(icon);
+ button2.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ button2.setButtonRenderer(renderer);
+
+ final OButton button3 = new OButton(shell, SWT.PUSH);
+ button3.setImage(icon);
+ button3.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ button3.setButtonRenderer(renderer);
+
+ final OButton button4 = new OButton(shell, SWT.TOGGLE);
+ button4.setText("Toggle button");
+ button4.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ button4.setButtonRenderer(renderer);
+
+ final OButton button5 = new OButton(shell, SWT.TOGGLE);
+ button5.setText("Disabled");
+ button5.setEnabled(false);
+ button5.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ button5.setButtonRenderer(renderer);
+
+ final int[] arrows = new int[] { SWT.LEFT, SWT.UP, SWT.RIGHT, SWT.DOWN };
+ for (final int arrow : arrows) {
+ final OButton button = new OButton(shell, SWT.ARROW | arrow);
+ button.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ button.setButtonRenderer(renderer);
+ }
+
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/obutton/user.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/obutton/user.png
new file mode 100644
index 0000000..212cb86
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/obutton/user.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/opalDialog/OpalDialogSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/opalDialog/OpalDialogSnippet.java
new file mode 100644
index 0000000..8d09108
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/opalDialog/OpalDialogSnippet.java
@@ -0,0 +1,427 @@
+/*******************************************************************************
+ * 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
+ * Eugene Ryzhikov - Author of the Oxbow Project (http://code.google.com/p/oxbow/) - Inspiration
+ *******************************************************************************/
+package org.mihalis.opal.opalDialog;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.opalDialog.Dialog.OpalDialogType;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the OpalDialog component
+ *
+ */
+public class OpalDialogSnippet {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+
+ final Shell shell = new Shell(display);
+ shell.setText("Dialog Sample");
+ shell.setLayout(new GridLayout(3, true));
+
+ final Button button1 = new Button(shell, SWT.PUSH);
+ button1.setText("Hello world !");
+ button1.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button1.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayHelloWorld();
+ }
+ });
+
+ final Button button2 = new Button(shell, SWT.PUSH);
+ button2.setText("Crash and burn");
+ button2.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button2.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayCrashAndBurn();
+ }
+ });
+
+ final Button button3 = new Button(shell, SWT.PUSH);
+ button3.setText("You won !");
+ button3.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button3.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayYouWon();
+ }
+ });
+
+ final Button button4 = new Button(shell, SWT.PUSH);
+ button4.setText("Confirm exit");
+ button4.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button4.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayConfirmExit();
+ }
+ });
+
+ final Button button5 = new Button(shell, SWT.PUSH);
+ button5.setText("Radio choice");
+ button5.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button5.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayRadioChoice();
+ }
+ });
+
+ final Button button6 = new Button(shell, SWT.PUSH);
+ button6.setText("Exception viewer");
+ button6.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button6.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayException();
+ }
+ });
+
+ final Button button7 = new Button(shell, SWT.PUSH);
+ button7.setText("Input box");
+ button7.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button7.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayInput();
+ }
+ });
+
+ final Button button8 = new Button(shell, SWT.PUSH);
+ button8.setText("Choice...");
+ button8.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button8.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayChoice();
+ }
+ });
+
+ final Button button9 = new Button(shell, SWT.PUSH);
+ button9.setText("Delayed quit");
+ button9.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button9.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayDelayedQuit();
+ }
+ });
+
+ final Button button10 = new Button(shell, SWT.PUSH);
+ button10.setText("Progress bar");
+ button10.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button10.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayProgressBar();
+ }
+ });
+
+ final Button button11 = new Button(shell, SWT.PUSH);
+ button11.setText("Complex Example 1");
+ button11.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button11.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displaySecurityWarning();
+ }
+ });
+
+ final Button button12 = new Button(shell, SWT.PUSH);
+ button12.setText("Complex Example 2");
+ button12.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button12.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayComplex();
+ }
+ });
+
+ final Button button13 = new Button(shell, SWT.PUSH);
+ button13.setText("Large Text Example");
+ button13.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button13.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ displayLargeText();
+ }
+ });
+
+ final Button button14 = new Button(shell, SWT.PUSH);
+ button14.setText("Issue 29");
+ button14.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button14.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ testIssue29();
+ }
+ });
+
+ final Button button15 = new Button(shell, SWT.PUSH);
+ button15.setText("Issue 45");
+ button15.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false));
+ button15.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ testIssue45();
+ }
+ });
+
+ // Open the shell
+ shell.pack();
+ SWTGraphicUtil.centerShell(shell);
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+
+ }
+
+ private static void displayHelloWorld() {
+ final Dialog dialog = new Dialog();
+ dialog.getMessageArea().setText("Hello world");
+ dialog.setButtonType(OpalDialogType.OK);
+ dialog.show();
+
+ }
+
+ private static void displayCrashAndBurn() {
+ Dialog.error("CRASH AND BURN !", "The application has performed an illegal action. This action has been logged and reported.");
+ }
+
+ private static void displayYouWon() {
+ Dialog.inform("You've won!", "The game is over with the 15:3 score");
+
+ }
+
+ private static void displayConfirmExit() {
+ final boolean confirm = Dialog.isConfirmed("Are you sure you want to quit?", "Please do not quit yet!");
+ System.out.println("Choice is..." + confirm);
+ }
+
+ private static void displayRadioChoice() {
+ final int choice = Dialog.radioChoice("You've got selection to make", "Go ahead", 1, "Yes", "No", "May be");
+ System.out.println("Choice is..." + choice);
+ }
+
+ private static void displayException() {
+
+ try {
+ new BigDecimal("seven"); // NOSONAR
+ } catch (final Exception ex) { // catching 'Exception' instead of 'Throwable' to satisfy SONAR!
+ Dialog.showException(ex);
+ }
+ }
+
+ private static void displayChoice() {
+ final int choice = Dialog.choice("What do you want to do with your game in\nprogress?", "", 1, new ChoiceItem("Exit and save my game", "Save your game in progress, then exit. " + "This will\noverwrite any previously saved games."),
+ new ChoiceItem("Exit and don't save", "Exit without saving your game. " + "This is counted\nas a loss in your statistics."), new ChoiceItem("Don't exit", "Return to your game progress"));
+ System.out.println("Choice is..." + choice);
+ }
+
+ private static void displayDelayedQuit() {
+ final boolean choice = Dialog.isConfirmed("Are you sure you want to quit?", "Please do not quit yet!", 10);
+ System.out.println("Choice is..." + choice);
+
+ }
+
+ private static void displaySecurityWarning() {
+ final Dialog dialog = new Dialog();
+ dialog.setTitle("Security Warning");
+ dialog.setMinimumWidth(400);
+ dialog.getMessageArea().setTitle("The publisher cannot be verified.\nDo you want to run this software?") //
+ .setIcon(Display.getCurrent().getSystemImage(SWT.ICON_WARNING)) //
+ .setText("Name: C:\\Program Files\\eclipse\\eclipse.exe<br/>" + //
+ "Publisher: <b>Unknown Publisher</b><br/>" + //
+ "Type: Application<br/>");
+
+ dialog.getFooterArea().addCheckBox("Always ask before opening this file", false).setButtonLabels("Run", "Cancel");
+ dialog.show();
+
+ System.out.println("The choice is " + dialog.getSelectedButton() + ", the checkbox value is " + dialog.getCheckboxValue());
+
+ }
+
+ private static void displayProgressBar() {
+ final Dialog dialog = new Dialog();
+ dialog.setTitle("Copying...");
+ dialog.setMinimumWidth(400);
+ dialog.getMessageArea().setTitle("Copying files") //
+ .setIcon(Display.getCurrent().getSystemImage(SWT.ICON_INFORMATION)) //
+ .setText("Location : from 'Others' to 'Others'<br/>" + //
+ "File Name : <b>photo.jpg</b>")
+ .//
+ addProgressBar(0, 100, 0);
+
+ final int[] counter = new int[1];
+ counter[0] = 10;
+
+ Display.getCurrent().timerExec(500, new Runnable() {
+
+ @Override
+ public void run() {
+ dialog.getMessageArea().setProgressBarValue(counter[0]);
+ dialog.getMessageArea().setText("Location : from 'Others' to 'Others'<br/>" + //
+ "File Name : <b>photo" + counter[0] + ".jpg</b>");
+ counter[0] += 10;
+ if (counter[0] < 120) {
+ Display.getCurrent().timerExec(500, this);
+ } else {
+ dialog.close();
+ }
+ }
+ });
+
+ dialog.show();
+
+ }
+
+ private static void displayInput() {
+ final String input = Dialog.ask("Enter you name", "or any other text if you prefer", "Laurent CARON");
+ System.out.println("Choice is..." + input);
+
+ }
+
+ private static void displayComplex() {
+ final Dialog dialog = new Dialog();
+ dialog.setTitle("Application Error");
+ dialog.getMessageArea().setTitle("CRASH AND BURN !").//
+ setText("The application has performed an illegal action. This action has been logged and reported.").//
+ setIcon(Display.getCurrent().getSystemImage(SWT.ICON_ERROR));
+ dialog.setButtonType(OpalDialogType.OK);
+ dialog.getFooterArea().setExpanded(false).addCheckBox("Don't show me this error next time", true).setDetailText("More explanations to come...");
+ dialog.getFooterArea().setFooterText("Your application crashed because a developer forgot to write a unit test").//
+ setIcon(SWTGraphicUtil.createImageFromFile("org/mihalis/opal/OpalDialog/warning.png"));
+ dialog.show();
+
+ }
+
+ private static void displayLargeText() {
+ final StringBuilder stringBuilder = new StringBuilder();
+ for (int t = 0; t < 20; t++) {
+ stringBuilder.append("A <b>very</b> <size=10>long text (10)</size> " + t + "");
+ stringBuilder.append("A <b>very</b> <size=+12>long text (+12)</size> " + t + "");
+ stringBuilder.append("A <b>very</b> <size=-4>long text (-4)</size> " + t + "");
+ stringBuilder.append("A <b>very</b> <color=#088A29>long text</color> " + t + "");
+ stringBuilder.append("A <b>very</b> <color=255,0,255>long text</color> " + t + "");
+ stringBuilder.append("A <b>very</b> <color=navy>long text</color> " + t + "");
+ stringBuilder.append("A <b>very</b> <backgroundcolor=255,0,0>long text</backgroundcolor> " + t + "");
+ stringBuilder.append("A <b>very</b> <backgroundcolor=#FFFFCC>long text</backgroundcolor> " + t + "");
+ stringBuilder.append("A <b>very</b> <backgroundcolor=lavender>long text</backgroundcolor> " + t + "");
+ stringBuilder.append("A very long text " + t + "<br/>");
+ stringBuilder.append("..." + "<br/>");
+ }
+
+ final Dialog dialog = new Dialog(true);
+ dialog.getMessageArea().setVerticalScrollbar(true);
+ dialog.getMessageArea().setHeight(200);
+ dialog.getMessageArea().setText(stringBuilder.toString());
+ dialog.setButtonType(OpalDialogType.OK);
+ dialog.show();
+ }
+
+ private static void testIssue29() {
+ final Dialog d = new Dialog();
+ d.setCenterPolicy(Dialog.CenterOption.CENTER_ON_DIALOG);
+ d.setTitle("foo title");
+
+ d.getMessageArea().setTitle("aaaa").setText("bbbb");
+
+ d.getFooterArea().setButtonLabels(Arrays.asList("Don't Save please", "Cancel"));
+ d.show();
+
+ }
+
+ private static void testIssue45() {
+
+ final Dialog dialog = new Dialog(true);
+ dialog.getMessageArea().setVerticalScrollbar(true);
+ dialog.getMessageArea().setHeight(200);
+ dialog.getMessageArea().setText("Illegal format <key>:<value>");
+ dialog.setButtonType(OpalDialogType.OK);
+ dialog.show();
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/opalDialog/warning.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/opalDialog/warning.png
new file mode 100644
index 0000000..6a0398d
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/opalDialog/warning.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/panels/SnippetBlurredPanel.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/panels/SnippetBlurredPanel.java
new file mode 100644
index 0000000..989ad69
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/panels/SnippetBlurredPanel.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * 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.panels;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+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.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.opalDialog.Dialog;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the blured panel
+ *
+ */
+public class SnippetBlurredPanel {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell();
+ shell.setText("Blured Panel Sample");
+ shell.setLayout(new GridLayout(2, false));
+
+ createRow(shell, "First Name");
+ createRow(shell, "Last Name");
+ createRow(shell, "E-mail");
+ createRow(shell, "Phone number");
+
+ createButtons(shell);
+
+ shell.setSize(shell.computeSize(400, 400));
+ SWTGraphicUtil.centerShell(shell);
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+ private static void createRow(final Shell shell, final String label) {
+ final Label lbl = new Label(shell, SWT.NONE);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));
+
+ final Text text = new Text(shell, SWT.SINGLE | SWT.BORDER);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ }
+
+ private static void createButtons(final Shell shell) {
+ final BlurredPanel p = new BlurredPanel(shell);
+
+ final Composite composite = new Composite(shell, SWT.NONE);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+ composite.setLayout(new GridLayout(2, false));
+
+ final Button ok = new Button(composite, SWT.PUSH);
+ ok.setText("Ok");
+ ok.setLayoutData(new GridData(SWT.END, SWT.END, true, true));
+ ok.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+
+ p.show();
+ Dialog.isConfirmed("Confirmation", "Are you sure you want to save this form ?");
+ p.hide();
+ }
+
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ }
+ });
+
+ final Button cancel = new Button(composite, SWT.PUSH);
+ cancel.setText("Cancel");
+ cancel.setLayoutData(new GridData(SWT.CENTER, SWT.END, false, true));
+ cancel.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ shell.dispose();
+ }
+
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ shell.dispose();
+ }
+ });
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/panels/SnippetDarkPanel.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/panels/SnippetDarkPanel.java
new file mode 100644
index 0000000..a375883
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/panels/SnippetDarkPanel.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * 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.panels;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+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.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.opalDialog.Dialog;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the dark panel
+ *
+ */
+public class SnippetDarkPanel {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell();
+ shell.setText("Dark Panel Sample");
+ shell.setLayout(new GridLayout(2, false));
+
+ createRow(shell, "First Name");
+ createRow(shell, "Last Name");
+ createRow(shell, "E-mail");
+ createRow(shell, "Phone number");
+
+ createButtons(shell);
+
+ shell.setSize(shell.computeSize(400, 400));
+ SWTGraphicUtil.centerShell(shell);
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+ private static void createRow(final Shell shell, final String label) {
+ final Label lbl = new Label(shell, SWT.NONE);
+ lbl.setText(label);
+ lbl.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));
+
+ final Text text = new Text(shell, SWT.SINGLE | SWT.BORDER);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ }
+
+ private static void createButtons(final Shell shell) {
+ final DarkPanel p = new DarkPanel(shell);
+
+ final Composite composite = new Composite(shell, SWT.NONE);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+ composite.setLayout(new GridLayout(2, false));
+
+ final Button ok = new Button(composite, SWT.PUSH);
+ ok.setText("Ok");
+ ok.setLayoutData(new GridData(SWT.END, SWT.END, true, true));
+ ok.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+
+ p.show();
+ Dialog.isConfirmed("Confirmation", "Are you sure you want to save this form ?");
+ p.hide();
+ }
+
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ }
+ });
+
+ final Button cancel = new Button(composite, SWT.PUSH);
+ cancel.setText("Cancel");
+ cancel.setLayoutData(new GridData(SWT.CENTER, SWT.END, false, true));
+ cancel.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ shell.dispose();
+ }
+
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ shell.dispose();
+ }
+ });
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/PreferenceWindowSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/PreferenceWindowSnippet.java
new file mode 100644
index 0000000..e905347
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/PreferenceWindowSnippet.java
@@ -0,0 +1,278 @@
+/*******************************************************************************
+ * 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.preferenceWindow;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.opalDialog.Dialog;
+import org.mihalis.opal.preferenceWindow.enabler.EnabledIfEquals;
+import org.mihalis.opal.preferenceWindow.enabler.EnabledIfTrue;
+import org.mihalis.opal.preferenceWindow.widgets.PWButton;
+import org.mihalis.opal.preferenceWindow.widgets.PWCheckbox;
+import org.mihalis.opal.preferenceWindow.widgets.PWColorChooser;
+import org.mihalis.opal.preferenceWindow.widgets.PWCombo;
+import org.mihalis.opal.preferenceWindow.widgets.PWDirectoryChooser;
+import org.mihalis.opal.preferenceWindow.widgets.PWFileChooser;
+import org.mihalis.opal.preferenceWindow.widgets.PWFloatText;
+import org.mihalis.opal.preferenceWindow.widgets.PWFontChooser;
+import org.mihalis.opal.preferenceWindow.widgets.PWIntegerText;
+import org.mihalis.opal.preferenceWindow.widgets.PWLabel;
+import org.mihalis.opal.preferenceWindow.widgets.PWPasswordText;
+import org.mihalis.opal.preferenceWindow.widgets.PWRadio;
+import org.mihalis.opal.preferenceWindow.widgets.PWScale;
+import org.mihalis.opal.preferenceWindow.widgets.PWSeparator;
+import org.mihalis.opal.preferenceWindow.widgets.PWSpinner;
+import org.mihalis.opal.preferenceWindow.widgets.PWStringText;
+import org.mihalis.opal.preferenceWindow.widgets.PWTextarea;
+import org.mihalis.opal.preferenceWindow.widgets.PWURLText;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the PreferenceWindow widget
+ *
+ */
+public class PreferenceWindowSnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+
+ Locale.setDefault(Locale.ENGLISH);
+
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("PreferenceWindow snippet");
+ shell.setLayout(new FillLayout(SWT.VERTICAL));
+
+ final Button button1 = new Button(shell, SWT.PUSH);
+ button1.setText("Open preference window");
+
+ final Map<String, Object> data = fillData();
+
+ button1.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ final PreferenceWindow window = PreferenceWindow.create(shell, data);
+
+ createDocumentTab(window);
+ createInfoTab(window);
+ createTerminalTab(window);
+ createPrinterTab(window);
+ createSystemTab(window);
+
+ window.setSelectedTab(2);
+
+ window.open();
+ }
+ });
+
+ shell.pack();
+ shell.open();
+ SWTGraphicUtil.centerShell(shell);
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+
+ private static Map<String, Object> fillData() {
+ final Map<String, Object> data = new HashMap<String, Object>();
+ data.put("text", "A string");
+ data.put("int", new Integer(42)); // NOSONAR
+ data.put("float", new Float(3.14));
+ data.put("url", "http://www.google.fr/");
+ data.put("password", "password"); // NOSONAR
+ data.put("directory", "");
+ data.put("file", "");
+ data.put("textarea", "long long\nlong long\nlong long\ntext...");
+ data.put("comboReadOnly", "Value 1");
+ data.put("combo", "Other Value");
+
+ data.put("cb1", new Boolean(true));
+ // cb2 is not initialized
+ data.put("slider", new Integer(40));
+ data.put("spinner", new Integer(30));
+ data.put("color", new RGB(120, 15, 30));
+ // font is not initialized
+
+ data.put("radio", "Radio button 3");
+ data.put("cb3", new Boolean(true));
+
+ // cb4 to cb14 are not initialised
+
+ data.put("cacheSizeUnit", "Megabytes");
+ data.put("openMode", "Double click");
+
+ return data;
+ }
+
+ protected static void createDocumentTab(final PreferenceWindow window) {
+ final PWTab documentTab = window.addTab(
+ new Image(Display.getCurrent(),
+ PreferenceWindowSnippet.class.getClassLoader()
+ .getResourceAsStream("org/mihalis/opal/preferenceWindow/images/document.png")),
+ "Document");
+
+ documentTab.add(new PWLabel("Let's start with Text, Separator, Combo and button")).//
+ add(new PWStringText("String :", "text").setAlignment(GridData.FILL)).//
+ add(new PWIntegerText("Integer :", "int"));
+ documentTab.add(new PWFloatText("Float :", "float"));
+ documentTab.add(new PWURLText("URL :", "url"));
+ documentTab.add(new PWPasswordText("Password :", "password"));
+ documentTab.add(new PWDirectoryChooser("Directory :", "directory"));
+ documentTab.add(new PWFileChooser("File :", "file"));
+ documentTab.add(new PWTextarea("Textarea :", "textarea"));
+
+ documentTab.add(new PWSeparator());
+
+ documentTab.add(new PWCombo("Combo (read-only):", "comboReadOnly", "Value 1", "Value 2", "Value 3"));
+ documentTab
+ .add(new PWCombo("Combo (editable):", "combo", true, new Object[] { "Value 1", "Value 2", "Value 3" }));
+
+ documentTab.add(new PWSeparator("Titled separator"));
+ documentTab.add(new PWButton("First button", new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ Dialog.inform("Hi", "You pressed the first button");
+ }
+
+ }).setAlignment(GridData.END));
+ }
+
+ protected static void createInfoTab(final PreferenceWindow window) {
+ final PWTab infoTab = window.addTab(new Image(Display.getCurrent(), PreferenceWindowSnippet.class
+ .getClassLoader().getResourceAsStream("org/mihalis/opal/preferenceWindow/images/info.png")), "Info");
+
+ infoTab.add(new PWLabel("Checkboxes, Slider,Spinner, Color chooser, Font chooser"));
+ infoTab.add(new PWCheckbox("Checkbox 1", "cb1"));
+ infoTab.add(new PWCheckbox("Checkbox 2", "cb2"));
+
+ infoTab.add(new PWSeparator());
+
+ infoTab.add(new PWScale("Slider : ", "slider", 0, 100, 10));
+ infoTab.add(new PWSpinner("Spinner :", "spinner", 0, 100));
+
+ infoTab.add(new PWSeparator());
+
+ infoTab.add(new PWColorChooser("Color :", "color"));
+ infoTab.add(new PWFontChooser("Font :", "font"));
+
+ }
+
+ protected static void createTerminalTab(final PreferenceWindow window) {
+ final PWTab terminalTab = window.addTab(
+ new Image(Display.getCurrent(),
+ PreferenceWindowSnippet.class.getClassLoader()
+ .getResourceAsStream("org/mihalis/opal/preferenceWindow/images/openterm.png")),
+ "Terminal");
+
+ terminalTab.add(new PWLabel("Group, radio, indentation and group of buttons in a row"));
+
+ final PWGroup group = new PWGroup("Group of buttons");
+ group.add(new PWRadio("Radio buttons:", "radio", "Radio button 1", "Radio button 2", "Radio button 3"));
+ terminalTab.add(group);
+
+ terminalTab.add(new PWCheckbox("Checkbox 3 (indented)", "cb3").setIndent(30).setWidth(200));
+
+ terminalTab.add(new PWRow().//
+ add(new PWButton("First button", new SelectionAdapter() {
+ })).//
+ add(new PWButton("Second button", new SelectionAdapter() {
+ })).//
+ add(new PWButton("Third button", new SelectionAdapter() {
+ })));
+
+ }
+
+ protected static void createPrinterTab(final PreferenceWindow window) {
+ final PWTab printerTab = window.addTab(
+ new Image(Display.getCurrent(),
+ PreferenceWindowSnippet.class.getClassLoader()
+ .getResourceAsStream("org/mihalis/opal/preferenceWindow/images/printer.png")),
+ "Printer");
+
+ printerTab.add(new PWLabel("Play <i>with</i> <b>checkboxes</b>"));
+
+ final PWGroup group = new PWGroup(false);
+ group.add(new PWRow().add(new PWCheckbox("First choice", "cb4")).add(new PWCheckbox("Second choice", "cb5")));
+ group.add(new PWRow().add(new PWCheckbox("Third choice", "cb6")).add(new PWCheckbox("Fourth choice", "cb7")));
+ group.add(new PWRow().add(new PWCheckbox("Fifth choice", "cb8")).add(new PWCheckbox("Sixth choice", "cb9")));
+ group.add(
+ new PWRow().add(new PWCheckbox("Seventh choice", "cb10")).add(new PWCheckbox("Eighth choice", "cb11")));
+ printerTab.add(group);
+
+ printerTab.add(new PWRow().//
+ add(new PWCheckbox("Automatically check for new versions", "cb12").setWidth(300)).//
+ add(new PWButton("Check for updates...", new SelectionAdapter() {
+ }).setWidth(250).setAlignment(GridData.END)));
+
+ printerTab.add(new PWSeparator());
+
+ final PWGroup group2 = new PWGroup(false);
+ group2.add(new PWRow().add(new PWLabel("Aligned checkbox")).add(new PWCheckbox("Bla bla bla 1", "cb13")));
+ group2.add(new PWRow().add(new PWLabel("")).add(new PWCheckbox("Bla bla bla 2", "cb14")));
+ printerTab.add(group2);
+ }
+
+ protected static void createSystemTab(final PreferenceWindow window) {
+ final PWTab systemTab = window.addTab(new Image(Display.getCurrent(), PreferenceWindowSnippet.class
+ .getClassLoader().getResourceAsStream("org/mihalis/opal/preferenceWindow/images/system.png")),
+ "System");
+
+ systemTab.add(new PWLabel("Rows..."));
+
+ systemTab.add(new PWRow()
+ .add(new PWCombo("Cache size", "cacheSize", true, new Object[] { "128", "256", "512", "1024" })).//
+ add(new PWCombo(null, "cacheSizeUnit", "Bytes", "Kilobytes", "Megabytes")));
+
+ systemTab.add(new PWRow().//
+ add(new PWCombo("Display:", "display", "10", "20", "30", "40", "50")).//
+ add(new PWLabel("per page")));
+
+ systemTab.add(new PWSeparator());
+
+ systemTab.add(new PWLabel("Enabled/disabled..."));
+
+ systemTab.add(new PWCheckbox("Show information", "show").setWidth(150));
+ systemTab.add(new PWGroup("Open Mode").setEnabler(new EnabledIfTrue("show")).//
+ add(new PWRadio(null, "openMode", "Double click", "Single click")).//
+ add(new PWCheckbox("Select on hover", "selectonhover").setIndent(10).setWidth(200)
+ .setEnabler(new EnabledIfEquals("openMode", "Single click")))
+ .//
+ add(new PWCheckbox("Open when using arrow keys", "openarrow").setIndent(10).setWidth(200)
+ .setEnabler(new EnabledIfEquals("openMode", "Single click"))));
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/document.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/document.png
new file mode 100644
index 0000000..a1dfa8e
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/document.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/info.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/info.png
new file mode 100644
index 0000000..ce7d067
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/info.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/openterm.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/openterm.png
new file mode 100644
index 0000000..7bf1e90
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/openterm.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/printer.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/printer.png
new file mode 100644
index 0000000..aa74ac5
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/printer.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/system.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/system.png
new file mode 100644
index 0000000..d734577
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/preferenceWindow/images/system.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/promptSupport/PromptSupportSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/promptSupport/PromptSupportSnippet.java
new file mode 100644
index 0000000..d8217be
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/promptSupport/PromptSupportSnippet.java
@@ -0,0 +1,309 @@
+/*******************************************************************************
+ * 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.promptSupport;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.promptSupport.PromptSupport.FocusBehavior;
+
+/**
+ * A simple snipper for the PromptSupport utilities
+ *
+ */
+public class PromptSupportSnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(2, true));
+
+ createText(new Group(shell, SWT.NONE));
+ createStyledText(new Group(shell, SWT.NONE));
+ createCombo(new Group(shell, SWT.NONE));
+ createCCombo(new Group(shell, SWT.NONE));
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+
+ }
+
+ private static void createText(final Group group) {
+ group.setLayout(new GridLayout(2, false));
+ group.setText("Text widget");
+
+ final Label lbl0 = new Label(group, SWT.NONE);
+ lbl0.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl0.setText("No prompt :");
+
+ final Text txt0 = new Text(group, SWT.BORDER);
+ txt0.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+
+ final Label lbl1 = new Label(group, SWT.NONE);
+ lbl1.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl1.setText("Simple text prompt :");
+
+ final Text txt1 = new Text(group, SWT.BORDER);
+ txt1.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", txt1);
+
+ final Label lbl2 = new Label(group, SWT.NONE);
+ lbl2.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl2.setText("Other style (bold) :");
+
+ final Text txt2 = new Text(group, SWT.BORDER);
+ txt2.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want in bold", txt2);
+ PromptSupport.setFontStyle(SWT.BOLD, txt2);
+
+ final Label lbl3 = new Label(group, SWT.NONE);
+ lbl3.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl3.setText("Behaviour highlight :");
+
+ final Text txt3 = new Text(group, SWT.BORDER);
+ txt3.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", txt3);
+ PromptSupport.setFocusBehavior(FocusBehavior.HIGHLIGHT_PROMPT, txt3);
+
+ final Label lbl4 = new Label(group, SWT.NONE);
+ lbl4.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl4.setText("Change colors :");
+
+ final Text txt4 = new Text(group, SWT.BORDER);
+ txt4.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", txt4);
+ PromptSupport.setForeground(txt4.getDisplay().getSystemColor(SWT.COLOR_YELLOW), txt4);
+ PromptSupport.setBackground(txt4.getDisplay().getSystemColor(SWT.COLOR_BLACK), txt4);
+
+ final Label lbl5 = new Label(group, SWT.NONE);
+ lbl5.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl5.setText("Change when widget is initialized :");
+
+ final Text txt5 = new Text(group, SWT.BORDER);
+ txt5.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ txt5.setText("Remove what is typed...");
+ txt5.setBackground(txt4.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ txt5.setForeground(txt4.getDisplay().getSystemColor(SWT.COLOR_YELLOW));
+
+ PromptSupport.setPrompt("Type anything you want", txt5);
+ PromptSupport.setForeground(txt4.getDisplay().getSystemColor(SWT.COLOR_DARK_BLUE), txt5);
+ PromptSupport.setBackground(txt4.getDisplay().getSystemColor(SWT.COLOR_WHITE), txt5);
+
+ }
+
+ private static void createStyledText(final Group group) {
+ group.setLayout(new GridLayout(2, false));
+ group.setText("StyledText widget");
+
+ final Label lbl0 = new Label(group, SWT.NONE);
+ lbl0.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl0.setText("No prompt :");
+
+ final StyledText txt0 = new StyledText(group, SWT.BORDER);
+ txt0.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+
+ final Label lbl1 = new Label(group, SWT.NONE);
+ lbl1.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl1.setText("Simple text prompt :");
+
+ final StyledText txt1 = new StyledText(group, SWT.BORDER);
+ txt1.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", txt1);
+
+ final Label lbl2 = new Label(group, SWT.NONE);
+ lbl2.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl2.setText("Other style (bold) :");
+
+ final StyledText txt2 = new StyledText(group, SWT.BORDER);
+ txt2.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want in bold", txt2);
+ PromptSupport.setFontStyle(SWT.BOLD, txt2);
+
+ final Label lbl3 = new Label(group, SWT.NONE);
+ lbl3.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl3.setText("Behaviour highlight :");
+
+ final StyledText txt3 = new StyledText(group, SWT.BORDER);
+ txt3.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", txt3);
+ PromptSupport.setFocusBehavior(FocusBehavior.HIGHLIGHT_PROMPT, txt3);
+
+ final Label lbl4 = new Label(group, SWT.NONE);
+ lbl4.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl4.setText("Change colors :");
+
+ final StyledText txt4 = new StyledText(group, SWT.BORDER);
+ txt4.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", txt4);
+ PromptSupport.setForeground(txt4.getDisplay().getSystemColor(SWT.COLOR_YELLOW), txt4);
+ PromptSupport.setBackground(txt4.getDisplay().getSystemColor(SWT.COLOR_BLACK), txt4);
+
+ final Label lbl5 = new Label(group, SWT.NONE);
+ lbl5.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl5.setText("Change when widget is initialized :");
+
+ final StyledText txt5 = new StyledText(group, SWT.BORDER);
+ txt5.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ txt5.setText("Remove what is typed...");
+ txt5.setBackground(txt4.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ txt5.setForeground(txt4.getDisplay().getSystemColor(SWT.COLOR_YELLOW));
+
+ PromptSupport.setPrompt("Type anything you want", txt5);
+ PromptSupport.setForeground(txt4.getDisplay().getSystemColor(SWT.COLOR_DARK_BLUE), txt5);
+ PromptSupport.setBackground(txt4.getDisplay().getSystemColor(SWT.COLOR_WHITE), txt5);
+
+ }
+
+ private static void createCombo(final Group group) {
+ group.setLayout(new GridLayout(2, false));
+ group.setText("Combo widget");
+
+ final Label lbl0 = new Label(group, SWT.NONE);
+ lbl0.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl0.setText("No prompt :");
+
+ final Combo combo0 = new Combo(group, SWT.BORDER);
+ combo0.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+
+ final Label lbl1 = new Label(group, SWT.NONE);
+ lbl1.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl1.setText("Simple text prompt :");
+
+ final Combo combo1 = new Combo(group, SWT.BORDER);
+ combo1.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", combo1);
+
+ final Label lbl2 = new Label(group, SWT.NONE);
+ lbl2.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl2.setText("Other style (bold) :");
+
+ final Combo combo2 = new Combo(group, SWT.BORDER);
+ combo2.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want in bold", combo2);
+ PromptSupport.setFontStyle(SWT.BOLD, combo2);
+
+ final Label lbl3 = new Label(group, SWT.NONE);
+ lbl3.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl3.setText("Behaviour highlight :");
+
+ final Combo combo3 = new Combo(group, SWT.BORDER);
+ combo3.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", combo3);
+ PromptSupport.setFocusBehavior(FocusBehavior.HIGHLIGHT_PROMPT, combo3);
+
+ final Label lbl4 = new Label(group, SWT.NONE);
+ lbl4.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl4.setText("Change colors :");
+
+ final Combo combo4 = new Combo(group, SWT.BORDER);
+ combo4.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", combo4);
+ PromptSupport.setForeground(combo4.getDisplay().getSystemColor(SWT.COLOR_YELLOW), combo4);
+ PromptSupport.setBackground(combo4.getDisplay().getSystemColor(SWT.COLOR_BLACK), combo4);
+
+ final Label lbl5 = new Label(group, SWT.NONE);
+ lbl5.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl5.setText("Change when widget is initialized :");
+
+ final Combo combo5 = new Combo(group, SWT.BORDER);
+ combo5.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ combo5.setText("Remove what is typed...");
+ combo5.setBackground(combo4.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ combo5.setForeground(combo4.getDisplay().getSystemColor(SWT.COLOR_YELLOW));
+
+ PromptSupport.setPrompt("Type anything you want", combo5);
+ PromptSupport.setForeground(combo4.getDisplay().getSystemColor(SWT.COLOR_DARK_BLUE), combo5);
+ PromptSupport.setBackground(combo4.getDisplay().getSystemColor(SWT.COLOR_WHITE), combo5);
+
+ }
+
+ private static void createCCombo(final Group group) {
+ group.setLayout(new GridLayout(2, false));
+ group.setText("CCombo widget");
+
+ final Label lbl0 = new Label(group, SWT.NONE);
+ lbl0.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl0.setText("No prompt :");
+
+ final CCombo combo0 = new CCombo(group, SWT.BORDER);
+ combo0.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+
+ final Label lbl1 = new Label(group, SWT.NONE);
+ lbl1.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl1.setText("Simple text prompt :");
+
+ final CCombo txt1 = new CCombo(group, SWT.BORDER);
+ txt1.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", txt1);
+
+ final Label lbl2 = new Label(group, SWT.NONE);
+ lbl2.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl2.setText("Other style (bold) :");
+
+ final CCombo txt2 = new CCombo(group, SWT.BORDER);
+ txt2.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want in bold", txt2);
+ PromptSupport.setFontStyle(SWT.BOLD, txt2);
+
+ final Label lbl3 = new Label(group, SWT.NONE);
+ lbl3.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl3.setText("Behaviour highlight :");
+
+ final CCombo txt3 = new CCombo(group, SWT.BORDER);
+ txt3.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", txt3);
+ PromptSupport.setFocusBehavior(FocusBehavior.HIGHLIGHT_PROMPT, txt3);
+
+ final Label lbl4 = new Label(group, SWT.NONE);
+ lbl4.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl4.setText("Change colors :");
+
+ final CCombo txt4 = new CCombo(group, SWT.BORDER);
+ txt4.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ PromptSupport.setPrompt("Type anything you want", txt4);
+ PromptSupport.setForeground(txt4.getDisplay().getSystemColor(SWT.COLOR_YELLOW), txt4);
+ PromptSupport.setBackground(txt4.getDisplay().getSystemColor(SWT.COLOR_BLACK), txt4);
+
+ final Label lbl5 = new Label(group, SWT.NONE);
+ lbl5.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ lbl5.setText("Change when widget is initialized :");
+
+ final CCombo txt5 = new CCombo(group, SWT.BORDER);
+ txt5.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ txt5.setText("Remove what is typed...");
+ txt5.setBackground(txt4.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ txt5.setForeground(txt4.getDisplay().getSystemColor(SWT.COLOR_YELLOW));
+
+ PromptSupport.setPrompt("Type anything you want", txt5);
+ PromptSupport.setForeground(txt4.getDisplay().getSystemColor(SWT.COLOR_DARK_BLUE), txt5);
+ PromptSupport.setBackground(txt4.getDisplay().getSystemColor(SWT.COLOR_WHITE), txt5);
+
+ }
+
+} \ No newline at end of file
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/propertyTable/PropertyTableSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/propertyTable/PropertyTableSnippet.java
new file mode 100644
index 0000000..203fe2f
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/propertyTable/PropertyTableSnippet.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * 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.propertyTable;
+
+import java.util.Locale;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.mihalis.opal.propertyTable.editor.PTCheckboxEditor;
+import org.mihalis.opal.propertyTable.editor.PTColorEditor;
+import org.mihalis.opal.propertyTable.editor.PTComboEditor;
+import org.mihalis.opal.propertyTable.editor.PTDateEditor;
+import org.mihalis.opal.propertyTable.editor.PTDimensionEditor;
+import org.mihalis.opal.propertyTable.editor.PTDirectoryEditor;
+import org.mihalis.opal.propertyTable.editor.PTFileEditor;
+import org.mihalis.opal.propertyTable.editor.PTFloatEditor;
+import org.mihalis.opal.propertyTable.editor.PTFontEditor;
+import org.mihalis.opal.propertyTable.editor.PTInsetsEditor;
+import org.mihalis.opal.propertyTable.editor.PTIntegerEditor;
+import org.mihalis.opal.propertyTable.editor.PTPasswordEditor;
+import org.mihalis.opal.propertyTable.editor.PTRectangleEditor;
+import org.mihalis.opal.propertyTable.editor.PTSpinnerEditor;
+import org.mihalis.opal.propertyTable.editor.PTURLEditor;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the PropertyTable widget
+ *
+ */
+public class PropertyTableSnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+
+ Locale.setDefault(Locale.ENGLISH);
+
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("PropertyTable snippet");
+ shell.setLayout(new FillLayout(SWT.VERTICAL));
+
+ final TabFolder tabFolder = new TabFolder(shell, SWT.BORDER);
+
+ final TabItem item1 = new TabItem(tabFolder, SWT.NONE);
+ item1.setText("First");
+ item1.setControl(buildPropertyTable(tabFolder, true, true, true));
+
+ final TabItem item2 = new TabItem(tabFolder, SWT.NONE);
+ item2.setText("Second");
+ item2.setControl(buildPropertyTable(tabFolder, false, true, false));
+
+ final TabItem item3 = new TabItem(tabFolder, SWT.NONE);
+ item3.setText("Third");
+ item3.setControl(buildPropertyTable(tabFolder, true, false, true));
+
+ final TabItem item4 = new TabItem(tabFolder, SWT.NONE);
+ item4.setText("Forth");
+ item4.setControl(buildPropertyTable(tabFolder, true, false, false));
+
+ shell.setSize(800, 600);
+ shell.open();
+ SWTGraphicUtil.centerShell(shell);
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+
+ /**
+ * Build a property table
+ *
+ * @param tabFolder
+ * tabFolder that holds the property table
+ * @param showButton
+ * if <code>true</code>, show buttons
+ * @param showAsCategory
+ * if <code>true</code>, show property as categories. If
+ * <code>false</code>, show property as a flat list
+ * @param showDescription
+ * if <code>true</code>, show description
+ * @return a property table
+ */
+ private static PropertyTable buildPropertyTable(final TabFolder tabFolder, final boolean showButton,
+ final boolean showAsCategory, final boolean showDescription) {
+ final PropertyTable table = new PropertyTable(tabFolder, SWT.NONE);
+
+ if (showButton) {
+ table.showButtons();
+ } else {
+ table.hideButtons();
+ }
+
+ if (showAsCategory) {
+ table.viewAsCategories();
+ } else {
+ table.viewAsFlatList();
+ }
+
+ if (showDescription) {
+ table.showDescription();
+ } else {
+ table.hideDescription();
+ }
+ table.addProperty(new PTProperty("id", "Identifier", "Description for identifier", "My id"))
+ .setCategory("General");
+ table.addProperty(new PTProperty("text", "Description", "Description for the description field", "blahblah..."))
+ .setCategory("General");
+ table.addProperty(new PTProperty("url", "URL:", "This is a nice <b>URL</b>", "http://www.google.com")
+ .setCategory("General")).setEditor(new PTURLEditor());
+ table.addProperty(
+ new PTProperty("password", "Password", "Enter your <i>password</i> and keep it secret...", "password"))
+ .setCategory("General").setEditor(new PTPasswordEditor());
+
+ table.addProperty(new PTProperty("int", "An integer", "Type any integer", "123")).setCategory("Number")
+ .setEditor(new PTIntegerEditor());
+ table.addProperty(new PTProperty("float", "A float", "Type any float", "123.45")).setCategory("Number")
+ .setEditor(new PTFloatEditor());
+ table.addProperty(new PTProperty("spinner", "Another integer", "Use a spinner to enter an integer"))
+ .setCategory("Number").setEditor(new PTSpinnerEditor(0, 100));
+
+ table.addProperty(new PTProperty("directory", "Directory", "Select a directory")).setCategory("Directory/File")
+ .setEditor(new PTDirectoryEditor());
+ table.addProperty(new PTProperty("file", "File", "Select a file")).setCategory("Directory/File")
+ .setEditor(new PTFileEditor());
+
+ table.addProperty(new PTProperty("comboReadOnly", "Combo (read-only)", "A simple combo with seasons"))
+ .setCategory("Combo")
+ .setEditor(new PTComboEditor(true, new Object[] { "Spring", "Summer", "Autumn", "Winter" }));
+ table.addProperty(new PTProperty("combo", "Combo", "A combo that is not read-only")).setCategory("Combo")
+ .setEditor(new PTComboEditor("Value 1", "Value 2", "Value 3"));
+
+ table.addProperty(new PTProperty("cb", "Checkbox", "A checkbox")).setCategory("Checkbox")
+ .setEditor(new PTCheckboxEditor()).setCategory("Checkbox");
+ table.addProperty(new PTProperty("cb2", "Checkbox (disabled)", "A disabled checkbox..."))
+ .setEditor(new PTCheckboxEditor()).setCategory("Checkbox").setEnabled(false);
+
+ table.addProperty(new PTProperty("color", "Color", "Pick it !")).setCategory("Misc")
+ .setEditor(new PTColorEditor());
+ table.addProperty(new PTProperty("font", "Font", "Pick again my friend")).setEditor(new PTFontEditor())
+ .setCategory("Misc");
+ table.addProperty(new PTProperty("dimension", "Dimension", "A dimension is composed of a width and a height"))
+ .setCategory("Misc").setEditor(new PTDimensionEditor());
+ table.addProperty(new PTProperty("rectangle", "Rectangle",
+ "A rectangle is composed of a position (x,y) and a dimension(width,height)")).setCategory("Misc")
+ .setEditor(new PTRectangleEditor());
+ table.addProperty(
+ new PTProperty("inset", "Inset", "An inset is composed of the following fields:top,left,bottom,right)"))
+ .setCategory("Misc").setEditor(new PTInsetsEditor());
+ table.addProperty(new PTProperty("date", "Date", "Well, is there something more to say ?")).setCategory("Misc")
+ .setEditor(new PTDateEditor());
+
+ return table;
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/propertyTable/PropertyTableSnippetRefresh.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/propertyTable/PropertyTableSnippetRefresh.java
new file mode 100644
index 0000000..c0924cf
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/propertyTable/PropertyTableSnippetRefresh.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * 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.propertyTable;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+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.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.propertyTable.editor.PTCheckboxEditor;
+import org.mihalis.opal.propertyTable.editor.PTColorEditor;
+import org.mihalis.opal.propertyTable.editor.PTComboEditor;
+import org.mihalis.opal.propertyTable.editor.PTDateEditor;
+import org.mihalis.opal.propertyTable.editor.PTDimensionEditor;
+import org.mihalis.opal.propertyTable.editor.PTDirectoryEditor;
+import org.mihalis.opal.propertyTable.editor.PTFileEditor;
+import org.mihalis.opal.propertyTable.editor.PTFloatEditor;
+import org.mihalis.opal.propertyTable.editor.PTFontEditor;
+import org.mihalis.opal.propertyTable.editor.PTInsetsEditor;
+import org.mihalis.opal.propertyTable.editor.PTIntegerEditor;
+import org.mihalis.opal.propertyTable.editor.PTPasswordEditor;
+import org.mihalis.opal.propertyTable.editor.PTRectangleEditor;
+import org.mihalis.opal.propertyTable.editor.PTSpinnerEditor;
+import org.mihalis.opal.propertyTable.editor.PTURLEditor;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the PropertyTable widget
+ *
+ */
+public class PropertyTableSnippetRefresh {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+
+ Locale.setDefault(Locale.ENGLISH);
+
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("PropertyTable snippet");
+ shell.setLayout(new GridLayout(2, true));
+
+ final Button button1 = new Button(shell, SWT.PUSH);
+ button1.setText("First set of values");
+ button1.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ final Button button2 = new Button(shell, SWT.PUSH);
+ button2.setText("Second set of values");
+ button2.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+
+ final PropertyTable table = buildPropertyTable(shell);
+ table.setLayoutData(new GridData(GridData.FILL, GridData.FILL, //
+ true, true, 2, 1));
+
+ button1.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ final Map<String, Object> map = table.getProperties();
+ map.put("id", "My id");
+ map.put("text", "blahblah...");
+ map.put("url", "http://www.google.com");
+ map.put("password", "password"); // NOSONAR
+ map.put("int", "123");
+ map.put("float", "123.45");
+ map.put("spinner", null);
+ map.put("directory", null);
+ map.put("file", null);
+ map.put("comboReadOnly", null);
+ map.put("combo", null);
+ map.put("cb", Boolean.FALSE);
+ map.put("color", null);
+ map.put("font", null);
+ map.put("dimension", null);
+ map.put("rectangle", null);
+ map.put("inset", null);
+ map.put("date", null);
+ table.setProperties(map);
+ }
+ });
+
+ button2.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ final Map<String, Object> map = table.getProperties();
+ map.put("id", "(2)My id");
+ map.put("text", "(2)blahblah...");
+ map.put("url", "(2)http://www.google.com");
+ map.put("password", "(2)password"); // NOSONAR
+ map.put("int", "1234");
+ map.put("float", "1234.56");
+ map.put("spinner", 12);
+ map.put("directory", "C:/temp");
+ map.put("file", "C:/temp/temp.txt");
+ map.put("comboReadOnly", "Summer");
+ map.put("combo", "Value 2");
+ map.put("cb", Boolean.TRUE);
+ map.put("color", null);
+ map.put("font", null);
+ map.put("dimension", null);
+ map.put("rectangle", null);
+ map.put("inset", null);
+ map.put("date", new Date());
+ table.setProperties(map);
+ }
+ });
+
+ shell.setSize(800, 600);
+ shell.open();
+ SWTGraphicUtil.centerShell(shell);
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+
+ /**
+ * Build a property table
+ */
+ private static PropertyTable buildPropertyTable(final Composite composite) {
+ final PropertyTable table = new PropertyTable(composite, SWT.NONE);
+
+ table.showButtons();
+ table.viewAsCategories();
+ table.showDescription();
+
+ table.addProperty(new PTProperty("id", "Identifier", "Description for identifier", "My id")).setCategory("General");
+ table.addProperty(new PTProperty("text", "Description", "Description for the description field", "blahblah...")).setCategory("General");
+ table.addProperty(new PTProperty("url", "URL:", "This is a nice <b>URL</b>", "http://www.google.com").setCategory("General")).setEditor(new PTURLEditor());
+ table.addProperty(new PTProperty("password", "Password", "Enter your <i>password</i> and keep it secret...", "password")).setCategory("General").setEditor(new PTPasswordEditor());
+
+ table.addProperty(new PTProperty("int", "An integer", "Type any integer", "123")).setCategory("Number").setEditor(new PTIntegerEditor());
+ table.addProperty(new PTProperty("float", "A float", "Type any float", "123.45")).setCategory("Number").setEditor(new PTFloatEditor());
+ table.addProperty(new PTProperty("spinner", "Another integer", "Use a spinner to enter an integer")).setCategory("Number").setEditor(new PTSpinnerEditor(0, 100));
+
+ table.addProperty(new PTProperty("directory", "Directory", "Select a directory")).setCategory("Directory/File").setEditor(new PTDirectoryEditor());
+ table.addProperty(new PTProperty("file", "File", "Select a file")).setCategory("Directory/File").setEditor(new PTFileEditor());
+
+ table.addProperty(new PTProperty("comboReadOnly", "Combo (read-only)", "A simple combo with seasons")).setCategory("Combo").setEditor(new PTComboEditor(true, new Object[] { "Spring", "Summer", "Autumn", "Winter" }));
+ table.addProperty(new PTProperty("combo", "Combo", "A combo that is not read-only")).setCategory("Combo").setEditor(new PTComboEditor("Value 1", "Value 2", "Value 3"));
+
+ table.addProperty(new PTProperty("cb", "Checkbox", "A checkbox")).setCategory("Checkbox").setEditor(new PTCheckboxEditor()).setCategory("Checkbox");
+ table.addProperty(new PTProperty("cb2", "Checkbox (disabled)", "A disabled checkbox...")).setEditor(new PTCheckboxEditor()).setCategory("Checkbox").setEnabled(false);
+
+ table.addProperty(new PTProperty("color", "Color", "Pick it !")).setCategory("Misc").setEditor(new PTColorEditor());
+ table.addProperty(new PTProperty("font", "Font", "Pick again my friend")).setEditor(new PTFontEditor()).setCategory("Misc");
+ table.addProperty(new PTProperty("dimension", "Dimension", "A dimension is composed of a width and a height")).setCategory("Misc").setEditor(new PTDimensionEditor());
+ table.addProperty(new PTProperty("rectangle", "Rectangle", "A rectangle is composed of a position (x,y) and a dimension(width,height)")).setCategory("Misc").setEditor(new PTRectangleEditor());
+ table.addProperty(new PTProperty("inset", "Inset", "An inset is composed of the following fields:top,left,bottom,right)")).setCategory("Misc").setEditor(new PTInsetsEditor());
+ table.addProperty(new PTProperty("date", "Date", "Well, is there something more to say ?")).setCategory("Misc").setEditor(new PTDateEditor());
+
+ return table;
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/rangeSlider/RangeSliderSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/rangeSlider/RangeSliderSnippet.java
new file mode 100644
index 0000000..939bb8c
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/rangeSlider/RangeSliderSnippet.java
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * 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.rangeSlider;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.mihalis.opal.titledSeparator.TitledSeparator;
+
+/**
+ * A simple snipper for the RangleSlider widget
+ *
+ */
+public class RangeSliderSnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout(SWT.HORIZONTAL));
+
+ createNormalSliders(new Group(shell, SWT.NONE));
+ createDisabledSliders(new Group(shell, SWT.NONE));
+ createDifferentSliders(new Group(shell, SWT.NONE));
+ createSlidersCanceledSelectionListener(new Group(shell, SWT.NONE));
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+
+ }
+
+ private static void createNormalSliders(final Group group) {
+ group.setLayout(new GridLayout(3, false));
+
+ final TitledSeparator tsh = new TitledSeparator(group, SWT.NONE);
+ tsh.setText("Horizontal Range Slider");
+ tsh.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1));
+
+ final RangeSlider hRangeSlider = new RangeSlider(group, SWT.HORIZONTAL);
+ final GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false, 1, 2);
+ gd.widthHint = 250;
+ hRangeSlider.setLayoutData(gd);
+ hRangeSlider.setMinimum(0);
+ hRangeSlider.setMaximum(100);
+ hRangeSlider.setLowerValue(0);
+ hRangeSlider.setUpperValue(60);
+
+ final Label hLabelLower = new Label(group, SWT.NONE);
+ hLabelLower.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ hLabelLower.setText("Lower Value:");
+
+ final Text hTextLower = new Text(group, SWT.BORDER);
+ hTextLower.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ hTextLower.setText(hRangeSlider.getLowerValue() + " ");
+ hTextLower.setEnabled(false);
+
+ final Label hLabelUpper = new Label(group, SWT.NONE);
+ hLabelUpper.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ hLabelUpper.setText("Upper Value:");
+
+ final Text hTextUpper = new Text(group, SWT.BORDER);
+ hTextUpper.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ hTextUpper.setText(hRangeSlider.getUpperValue() + " ");
+ hTextUpper.setEnabled(false);
+
+ hRangeSlider.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ hTextLower.setText(hRangeSlider.getLowerValue() + " ");
+ hTextUpper.setText(hRangeSlider.getUpperValue() + " ");
+ }
+ });
+
+ final TitledSeparator tsv = new TitledSeparator(group, SWT.NONE);
+ tsv.setText("Vertical Range Slider");
+ tsv.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1));
+
+ final RangeSlider vRangeSlider = new RangeSlider(group, SWT.VERTICAL);
+ final GridData gd2 = new GridData(GridData.CENTER, GridData.FILL, false, false, 1, 2);
+ gd2.heightHint = 300;
+ vRangeSlider.setLayoutData(gd2);
+
+ final Label vLabelLower = new Label(group, SWT.NONE);
+ vLabelLower.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ vLabelLower.setText("Lower Value:");
+
+ final Text vTextLower = new Text(group, SWT.BORDER);
+ vTextLower.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ vTextLower.setText(vRangeSlider.getLowerValue() + " ");
+ vTextLower.setEnabled(false);
+
+ final Label vLabelUpper = new Label(group, SWT.NONE);
+ vLabelUpper.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ vLabelUpper.setText("Upper Value:");
+
+ final Text vTextUpper = new Text(group, SWT.BORDER);
+ vTextUpper.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ vTextUpper.setText(vRangeSlider.getUpperValue() + " ");
+ vTextUpper.setEnabled(false);
+
+ vRangeSlider.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ vTextLower.setText(hRangeSlider.getLowerValue() + " ");
+ vTextUpper.setText(hRangeSlider.getUpperValue() + " ");
+ }
+ });
+
+ }
+
+ private static void createDisabledSliders(final Group group) {
+ group.setLayout(new GridLayout(3, false));
+
+ final TitledSeparator tsh = new TitledSeparator(group, SWT.NONE);
+ tsh.setText("Horizontal Range Slider, disabled");
+ tsh.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1));
+
+ final RangeSlider hRangeSlider = new RangeSlider(group, SWT.HORIZONTAL);
+ final GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false, 1, 2);
+ gd.widthHint = 250;
+ hRangeSlider.setLayoutData(gd);
+ hRangeSlider.setMinimum(0);
+ hRangeSlider.setMaximum(100);
+ hRangeSlider.setLowerValue(0);
+ hRangeSlider.setUpperValue(60);
+ hRangeSlider.setEnabled(false);
+
+ final Label hLabelLower = new Label(group, SWT.NONE);
+ hLabelLower.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ hLabelLower.setText("Lower Value:");
+
+ final Text hTextLower = new Text(group, SWT.BORDER);
+ hTextLower.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ hTextLower.setText(hRangeSlider.getLowerValue() + " ");
+ hTextLower.setEnabled(false);
+
+ final Label hLabelUpper = new Label(group, SWT.NONE);
+ hLabelUpper.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ hLabelUpper.setText("Upper Value:");
+
+ final Text hTextUpper = new Text(group, SWT.BORDER);
+ hTextUpper.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ hTextUpper.setText(hRangeSlider.getUpperValue() + " ");
+ hTextUpper.setEnabled(false);
+
+ final TitledSeparator tsv = new TitledSeparator(group, SWT.NONE);
+ tsv.setText("Vertical Range Slider, disabled");
+ tsv.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1));
+
+ final RangeSlider vRangeSlider = new RangeSlider(group, SWT.VERTICAL);
+ final GridData gd2 = new GridData(GridData.CENTER, GridData.FILL, false, false, 1, 2);
+ gd2.heightHint = 300;
+ vRangeSlider.setLayoutData(gd2);
+ vRangeSlider.setEnabled(false);
+
+ final Label vLabelLower = new Label(group, SWT.NONE);
+ vLabelLower.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ vLabelLower.setText("Lower Value:");
+
+ final Text vTextLower = new Text(group, SWT.BORDER);
+ vTextLower.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ vTextLower.setText(vRangeSlider.getLowerValue() + " ");
+ vTextLower.setEnabled(false);
+
+ final Label vLabelUpper = new Label(group, SWT.NONE);
+ vLabelUpper.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ vLabelUpper.setText("Upper Value:");
+
+ final Text vTextUpper = new Text(group, SWT.BORDER);
+ vTextUpper.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ vTextUpper.setText(vRangeSlider.getUpperValue() + " ");
+ vTextUpper.setEnabled(false);
+
+ }
+
+ private static void createDifferentSliders(final Group group) {
+ group.setLayout(new GridLayout(3, false));
+
+ final TitledSeparator tsh = new TitledSeparator(group, SWT.NONE);
+ tsh.setText("Horizontal Range Slider, between 100 and 1000, increment by 100");
+ tsh.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1));
+
+ final RangeSlider hRangeSlider = new RangeSlider(group, SWT.HORIZONTAL);
+ final GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false, 1, 2);
+ gd.widthHint = 250;
+ hRangeSlider.setLayoutData(gd);
+ hRangeSlider.setMinimum(100);
+ hRangeSlider.setMaximum(1000);
+ hRangeSlider.setLowerValue(200);
+ hRangeSlider.setUpperValue(800);
+ hRangeSlider.setIncrement(100);
+ hRangeSlider.setPageIncrement(200);
+
+ final Label hLabelLower = new Label(group, SWT.NONE);
+ hLabelLower.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ hLabelLower.setText("Lower Value:");
+
+ final Text hTextLower = new Text(group, SWT.BORDER);
+ hTextLower.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ hTextLower.setText(hRangeSlider.getLowerValue() + " ");
+ hTextLower.setEnabled(false);
+
+ final Label hLabelUpper = new Label(group, SWT.NONE);
+ hLabelUpper.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ hLabelUpper.setText("Upper Value:");
+
+ final Text hTextUpper = new Text(group, SWT.BORDER);
+ hTextUpper.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ hTextUpper.setText(hRangeSlider.getUpperValue() + " ");
+ hTextUpper.setEnabled(false);
+
+ final TitledSeparator tsv = new TitledSeparator(group, SWT.NONE);
+ tsv.setText("Vertical Range Slider, between 100 and 1000, increment by 100");
+ tsv.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1));
+
+ final RangeSlider vRangeSlider = new RangeSlider(group, SWT.VERTICAL);
+ final GridData gd2 = new GridData(GridData.CENTER, GridData.FILL, false, false, 1, 2);
+ gd2.heightHint = 300;
+ vRangeSlider.setLayoutData(gd2);
+ vRangeSlider.setMinimum(100);
+ vRangeSlider.setMaximum(1000);
+ vRangeSlider.setLowerValue(200);
+ vRangeSlider.setUpperValue(800);
+ vRangeSlider.setIncrement(100);
+ vRangeSlider.setPageIncrement(200);
+
+ final Label vLabelLower = new Label(group, SWT.NONE);
+ vLabelLower.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ vLabelLower.setText("Lower Value:");
+
+ final Text vTextLower = new Text(group, SWT.BORDER);
+ vTextLower.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ vTextLower.setText(vRangeSlider.getLowerValue() + " ");
+ vTextLower.setEnabled(false);
+
+ final Label vLabelUpper = new Label(group, SWT.NONE);
+ vLabelUpper.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ vLabelUpper.setText("Upper Value:");
+
+ final Text vTextUpper = new Text(group, SWT.BORDER);
+ vTextUpper.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ vTextUpper.setText(vRangeSlider.getUpperValue() + " ");
+ vTextUpper.setEnabled(false);
+
+ }
+
+ private static void createSlidersCanceledSelectionListener(final Group group) {
+ group.setLayout(new GridLayout(3, false));
+
+ final TitledSeparator tsh = new TitledSeparator(group, SWT.NONE);
+ tsh.setText("Horizontal Range Slider, cancel selection");
+ tsh.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1));
+
+ final RangeSlider hRangeSlider = new RangeSlider(group, SWT.HORIZONTAL);
+ final GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false, 1, 2);
+ gd.widthHint = 250;
+ hRangeSlider.setLayoutData(gd);
+ hRangeSlider.setMinimum(0);
+ hRangeSlider.setMaximum(100);
+ hRangeSlider.setLowerValue(0);
+ hRangeSlider.setUpperValue(60);
+
+ hRangeSlider.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ e.doit = false;
+ }
+ });
+
+ final Label hLabelLower = new Label(group, SWT.NONE);
+ hLabelLower.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ hLabelLower.setText("Lower Value:");
+
+ final Text hTextLower = new Text(group, SWT.BORDER);
+ hTextLower.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ hTextLower.setText(hRangeSlider.getLowerValue() + " ");
+ hTextLower.setEnabled(false);
+
+ final Label hLabelUpper = new Label(group, SWT.NONE);
+ hLabelUpper.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ hLabelUpper.setText("Upper Value:");
+
+ final Text hTextUpper = new Text(group, SWT.BORDER);
+ hTextUpper.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ hTextUpper.setText(hRangeSlider.getUpperValue() + " ");
+ hTextUpper.setEnabled(false);
+
+ final TitledSeparator tsv = new TitledSeparator(group, SWT.NONE);
+ tsv.setText("Vertical Range Slider, cancel selection");
+ tsv.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1));
+
+ final RangeSlider vRangeSlider = new RangeSlider(group, SWT.VERTICAL);
+ final GridData gd2 = new GridData(GridData.CENTER, GridData.FILL, false, false, 1, 2);
+ gd2.heightHint = 300;
+ vRangeSlider.setLayoutData(gd2);
+
+ final Label vLabelLower = new Label(group, SWT.NONE);
+ vLabelLower.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ vLabelLower.setText("Lower Value:");
+
+ final Text vTextLower = new Text(group, SWT.BORDER);
+ vTextLower.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ vTextLower.setText(vRangeSlider.getLowerValue() + " ");
+ vTextLower.setEnabled(false);
+
+ final Label vLabelUpper = new Label(group, SWT.NONE);
+ vLabelUpper.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false, 1, 1));
+ vLabelUpper.setText("Upper Value:");
+
+ final Text vTextUpper = new Text(group, SWT.BORDER);
+ vTextUpper.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, 1, 1));
+ vTextUpper.setText(vRangeSlider.getUpperValue() + " ");
+ vTextUpper.setEnabled(false);
+
+ vRangeSlider.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ e.doit = false;
+ }
+ });
+
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/RoundedToolbarSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/RoundedToolbarSnippet.java
new file mode 100644
index 0000000..b24eebd
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/RoundedToolbarSnippet.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * 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.roundedToolbar;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A simple snippet for the Rounded Toolbar Widget
+ */
+public class RoundedToolbarSnippet {
+
+ private static Color grey1;
+ private static Color grey2;
+ private static Image iconBubble1b;
+ private static Image iconBubble1w;
+ private static Image iconBubble2b;
+ private static Image iconBubble2w;
+ private static Image iconBubble3b;
+ private static Image iconBubble3w;
+ private static Image emailb;
+ private static Image emailw;
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("RoundedToolbar Snippet");
+ final GridLayout gridLayout = new GridLayout();
+ gridLayout.horizontalSpacing = 20;
+ shell.setLayout(gridLayout);
+
+ grey1 = new Color(display, 211, 211, 211);
+ grey2 = new Color(display, 255, 250, 250);
+
+ iconBubble1b = new Image(display, RoundedToolbarSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/roundedToolbar/icons/bubble1_b.png"));
+ iconBubble1w = new Image(display, RoundedToolbarSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/roundedToolbar/icons/bubble1_w.png"));
+
+ iconBubble2b = new Image(display, RoundedToolbarSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/roundedToolbar/icons/bubble2_b.png"));
+ iconBubble2w = new Image(display, RoundedToolbarSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/roundedToolbar/icons/bubble2_w.png"));
+
+ iconBubble3b = new Image(display, RoundedToolbarSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/roundedToolbar/icons/bubble3_b.png"));
+ iconBubble3w = new Image(display, RoundedToolbarSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/roundedToolbar/icons/bubble3_w.png"));
+
+ emailb = new Image(display, RoundedToolbarSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/roundedToolbar/icons/email_b.png"));
+ emailw = new Image(display, RoundedToolbarSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/roundedToolbar/icons/email_w.png"));
+
+ createFirstToolbar(shell);
+
+ createSecondToolbar(shell, false);
+
+ final RoundedToolbar toolbar = createSecondToolbar(shell, true);
+ final GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false);
+ gd.widthHint = SWT.DEFAULT;
+ gd.heightHint = 100;
+ toolbar.setLayoutData(gd);
+
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ grey1.dispose();
+ grey2.dispose();
+
+ iconBubble1b.dispose();
+ iconBubble1w.dispose();
+ iconBubble2b.dispose();
+ iconBubble2w.dispose();
+ iconBubble3b.dispose();
+ iconBubble3w.dispose();
+ emailb.dispose();
+ emailw.dispose();
+
+ display.dispose();
+
+ }
+
+ private static void createFirstToolbar(final Shell shell) {
+ final RoundedToolbar roundedToolBar = new RoundedToolbar(shell, SWT.NONE);
+
+ roundedToolBar.setMultiselection(true);
+ roundedToolBar.setBackground(grey1);
+ roundedToolBar.setCornerRadius(6);
+
+ roundedToolBar.addControlListener(new ControlListener() {
+
+ @Override
+ public void controlResized(final ControlEvent e) {
+ System.out.println(roundedToolBar.getSize());
+
+ }
+
+ @Override
+ public void controlMoved(final ControlEvent e) {
+ // TODO Auto-generated method stub
+
+ }
+ });
+
+ final RoundedToolItem item1 = new RoundedToolItem(roundedToolBar);
+ item1.setSelection(true);
+ item1.setTooltipText("Multiple ballons");
+ item1.setWidth(40);
+ item1.setSelectionImage(iconBubble3w);
+ item1.setImage(iconBubble3b);
+
+ final RoundedToolItem item2 = new RoundedToolItem(roundedToolBar);
+ item2.setTooltipText("Simple item");
+ item2.setSelectionImage(iconBubble1w);
+ item2.setImage(iconBubble1b);
+ item2.setWidth(40);
+
+ final RoundedToolItem item3 = new RoundedToolItem(roundedToolBar);
+ item3.setTooltipText("Lot of lines\r\n\r\nThis item has a line-break");
+ item3.setSelectionImage(iconBubble2w);
+ item3.setImage(iconBubble2b);
+ item3.setWidth(40);
+ }
+
+ private static RoundedToolbar createSecondToolbar(final Shell shell, final boolean verticalAlignment) {
+ final RoundedToolbar roundedToolBar2 = new RoundedToolbar(shell, SWT.NONE);
+ roundedToolBar2.setCornerRadius(8);
+ roundedToolBar2.setBackground(grey1);
+
+ final RoundedToolItem mailItem = new RoundedToolItem(roundedToolBar2);
+ mailItem.setSelectionImage(emailw);
+ mailItem.setImage(emailb);
+ mailItem.setWidth(32);
+ mailItem.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ System.out.println("Bar2/Button 1");
+ }
+ });
+ if (verticalAlignment) {
+ mailItem.setVerticalAlignment(SWT.TOP);
+ }
+
+ final RoundedToolItem mailItemWithText = new RoundedToolItem(roundedToolBar2);
+ mailItemWithText.setTextColorSelected(grey2);
+ mailItemWithText.setText("Mails");
+ mailItemWithText.setSelectionImage(emailw);
+ mailItemWithText.setImage(emailb);
+ mailItemWithText.setWidth(65);
+ mailItemWithText.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ System.out.println("Bar2/Button 2");
+ }
+ });
+ if (verticalAlignment) {
+ mailItemWithText.setVerticalAlignment(SWT.CENTER);
+ }
+
+ final RoundedToolItem itemJustText = new RoundedToolItem(roundedToolBar2);
+ itemJustText.setTextColorSelected(grey2);
+ itemJustText.setText("Just text");
+ itemJustText.setWidth(100);
+ itemJustText.setAlignment(SWT.RIGHT);
+ itemJustText.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ System.out.println("Bar2/Button 3");
+ }
+ });
+
+ if (verticalAlignment) {
+ itemJustText.setVerticalAlignment(SWT.BOTTOM);
+ }
+ return roundedToolBar2;
+
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble1_b.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble1_b.png
new file mode 100644
index 0000000..5c18490
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble1_b.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble1_w.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble1_w.png
new file mode 100644
index 0000000..649a14d
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble1_w.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble2_b.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble2_b.png
new file mode 100644
index 0000000..c53ed74
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble2_b.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble2_w.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble2_w.png
new file mode 100644
index 0000000..d0da76e
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble2_w.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble3_b.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble3_b.png
new file mode 100644
index 0000000..376f8af
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble3_b.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble3_w.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble3_w.png
new file mode 100644
index 0000000..56361b9
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/bubble3_w.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/email_b.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/email_b.png
new file mode 100644
index 0000000..5c8233d
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/email_b.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/email_w.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/email_w.png
new file mode 100644
index 0000000..26bb42b
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/roundedToolbar/icons/email_w.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/starRating/StarRatingSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/starRating/StarRatingSnippet.java
new file mode 100644
index 0000000..8bd8054
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/starRating/StarRatingSnippet.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * 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.starRating;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A simple snippet for the StarRating component
+ */
+public class StarRatingSnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("StarRating Snippet");
+
+ shell.setLayout(new GridLayout(2, false));
+
+ createHorizontal(shell, true);
+ createHorizontal(shell, false);
+
+ final Composite composite = new Composite(shell, SWT.NONE);
+ composite.setLayout(new GridLayout(8, false));
+ composite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1));
+
+ createVertical(composite, true);
+ createVertical(composite, false);
+
+ shell.pack();
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+
+ }
+
+ private static void createHorizontal(final Shell shell, final boolean enabled) {
+ for (final StarRating.SIZE size : StarRating.SIZE.values()) {
+ final Label label = new Label(shell, SWT.NONE);
+ label.setText("Horizontal " + (enabled ? "enabled" : "disabled") + " size=" + size.toString());
+ label.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+
+ final StarRating sr = new StarRating(shell, SWT.NONE);
+ final GridData gd = new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false);
+ sr.setLayoutData(gd);
+ sr.setSizeOfStars(size);
+ sr.setEnabled(enabled);
+ sr.setMaxNumberOfStars(5 + (enabled ? 1 : 0));
+ }
+ }
+
+ private static void createVertical(final Composite composite, final boolean enabled) {
+ for (final StarRating.SIZE size : StarRating.SIZE.values()) {
+ final Label label = new Label(composite, SWT.NONE);
+ label.setText("Vertical " + (enabled ? "enabled" : "disabled") + " size=" + size.toString());
+ label.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
+
+ final StarRating sr = new StarRating(composite, SWT.VERTICAL | SWT.BORDER);
+ sr.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false));
+ sr.setSizeOfStars(size);
+ sr.setEnabled(enabled);
+ sr.setMaxNumberOfStars(5 + (enabled ? 1 : 0));
+ }
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/switchButton/SwitchButtonSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/switchButton/SwitchButtonSnippet.java
new file mode 100644
index 0000000..62a5009
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/switchButton/SwitchButtonSnippet.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * 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.switchButton;
+
+import org.eclipse.swt.SWT;
+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.Font;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A simple snippet for the SwitchButton Widget
+ */
+public class SwitchButtonSnippet {
+
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("SwitchButton Snippet");
+ shell.setSize(600, 600);
+ shell.setLayout(new GridLayout(1, false));
+
+ // Default
+ final SwitchButton button1 = new SwitchButton(shell, SWT.NONE);
+ button1.setText("Default switchButton");
+
+ // With a border
+ final SwitchButton button2 = new SwitchButton(shell, SWT.NONE);
+ button2.setBorderColor(display.getSystemColor(SWT.COLOR_DARK_RED));
+ button2.setTextForSelect("Selected...");
+ button2.setTextForUnselect("Unselected...");
+ button2.setText("Default switchButton with border");
+
+ // Disabled
+ final SwitchButton button3 = new SwitchButton(shell, SWT.NONE);
+ button3.setEnabled(false);
+ button3.setText("Default switchButton disabled");
+
+ // Without glow effect
+ final SwitchButton button4 = new SwitchButton(shell, SWT.NONE);
+ button4.setFocusColor(null);
+ button4.setText("Default switchButton with no focus effect");
+
+ // No text
+ final SwitchButton button5 = new SwitchButton(shell, SWT.NONE);
+ button5.setSelection(true);
+ button5.setText("");
+
+ // Square
+ final SwitchButton button6 = new SwitchButton(shell, SWT.NONE);
+ button6.setRound(false);
+ button6.setText("Square");
+
+ // Full of color
+ final SwitchButton button7 = new SwitchButton(shell, SWT.NONE);
+ button7.setButtonBackgroundColor1(display.getSystemColor(SWT.COLOR_DARK_BLUE));
+ button7.setButtonBackgroundColor2(display.getSystemColor(SWT.COLOR_BLUE));
+ button7.setButtonBorderColor(display.getSystemColor(SWT.COLOR_RED));
+
+ button7.setSelectedBackgroundColor(display.getSystemColor(SWT.COLOR_BLACK));
+ button7.setSelectedForegroundColor(display.getSystemColor(SWT.COLOR_WHITE));
+
+ button7.setUnselectedBackgroundColor(display.getSystemColor(SWT.COLOR_RED));
+ button7.setUnselectedForegroundColor(display.getSystemColor(SWT.COLOR_GRAY));
+
+ button7.setText("New colors");
+
+ // Listeners
+ final SwitchButton button8 = new SwitchButton(shell, SWT.NONE);
+ button8.setText("Listeners...");
+ button8.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ System.out.println("Before clicking, the selection was... " + button8.getSelection());
+ }
+
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ }
+ });
+
+ // Listeners with doit=false !
+ final SwitchButton button9 = new SwitchButton(shell, SWT.NONE);
+ button9.setText("Listeners with doit = false...");
+ button9.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ System.out.println("I don't want this");
+ e.doit = false;
+ }
+
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ }
+ });
+
+ // Change font
+ final SwitchButton button10 = new SwitchButton(shell, SWT.NONE);
+ final Font font = new Font(display, "Courier New", 18, SWT.BOLD | SWT.ITALIC);
+ shell.addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ font.dispose();
+ }
+ });
+ button10.setFont(font);
+ button10.setText("New font");
+
+ // Change background & foreground color
+ final SwitchButton button11 = new SwitchButton(shell, SWT.NONE);
+ button11.setBackground(display.getSystemColor(SWT.COLOR_YELLOW));
+ button11.setForeground(display.getSystemColor(SWT.COLOR_RED));
+ button11.setText("And now for something completely different");
+
+ // Change margins
+ final SwitchButton button12 = new SwitchButton(shell, SWT.NONE);
+ button12.setInsideMargin(8, 2);
+ button12.setText("With bigger margins and arc");
+ button12.setArc(4);
+
+ // Register listener via Widget
+ final SwitchButton button13 = new SwitchButton(shell, SWT.NONE);
+ button13.setTextForSelect(" ");
+ button13.setTextForUnselect(" ");
+ button13.setInsideMargin(8, 2);
+ button13.setFocusColor(null);
+ button13.setText("No text, Using low level SWT observer functions");
+ button13.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ event.display.beep();
+ }
+ });
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/systemMonitor/RandomSample.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/systemMonitor/RandomSample.java
new file mode 100644
index 0000000..d5c4df9
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/systemMonitor/RandomSample.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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.systemMonitor;
+
+import java.util.Random;
+
+import org.mihalis.opal.systemMonitor.Sample;
+
+/**
+ * A random sample
+ */
+public class RandomSample implements Sample {
+
+ @Override
+ public double getValue() {
+ return new Random().nextInt(100);
+ }
+
+ @Override
+ public double getMaxValue() {
+ return 99d;
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/systemMonitor/SystemMonitorSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/systemMonitor/SystemMonitorSnippet.java
new file mode 100644
index 0000000..14cb689
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/systemMonitor/SystemMonitorSnippet.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * 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.systemMonitor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.systemMonitor.SampleIdentifier;
+import org.mihalis.opal.systemMonitor.SystemMonitor;
+
+/**
+ * A simple snippet for the SystemMonitor Widget
+ */
+public class SystemMonitorSnippet {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(3, false));
+
+ final SystemMonitor allWithoutCaption = new SystemMonitor(shell, SWT.NONE);
+ allWithoutCaption.displayAll();
+ allWithoutCaption.setCaptionVisible(false);
+ allWithoutCaption.setLayoutData(createLayoutData());
+
+ final SystemMonitor cpu = new SystemMonitor(shell, SWT.NONE, SampleIdentifier.CPU_USAGE);
+ cpu.setLayoutData(createLayoutData());
+
+ final SystemMonitor heap = new SystemMonitor(shell, SWT.NONE, SampleIdentifier.HEAP_MEMORY);
+ heap.setLayoutData(createLayoutData());
+
+ final SystemMonitor physical = new SystemMonitor(shell, SWT.NONE, SampleIdentifier.PHYSICAL_MEMORY);
+ physical.setLayoutData(createLayoutData());
+
+ final SystemMonitor threads = new SystemMonitor(shell, SWT.NONE, SampleIdentifier.THREADS);
+ threads.setLayoutData(createLayoutData());
+
+ final SystemMonitor custom = new SystemMonitor(shell, SWT.NONE);
+ custom.addSample("custom", new RandomSample());
+ custom.setCaption("custom", "Random value:");
+ custom.setColor("custom", new RGB(255, 255, 216));
+ custom.setFormatPattern("custom", "%{value},.0f / %{maxValue},.0f / %{percentValue}.0f%%");
+ custom.setLayoutData(createLayoutData());
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+ /**
+ * @return a layout data
+ */
+ private static GridData createLayoutData() {
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true);
+ gd.widthHint = 500;
+ gd.heightHint = 400;
+ return gd;
+ }
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/textAssist/TextAssistSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/textAssist/TextAssistSnippet.java
new file mode 100644
index 0000000..c29c7d3
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/textAssist/TextAssistSnippet.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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)
+ *******************************************************************************/
+package org.mihalis.opal.textAssist;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A simple snippet for the TextAssist Widget
+ */
+public class TextAssistSnippet {
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout());
+
+ final TextAssistContentProvider contentProvider = new TextAssistContentProvider() {
+
+ private final String[] EUROZONE = new String[] { "Austria", "Belgium", "Cyprus", "Estonia", "Finland", "France", "Germany", "Greece", "Ireland", "Italy", "Luxembourg", "Malta", "Netherlands", "Portugal", "Slovakia", "Slovenia", "Spain" };
+
+ @Override
+ public List<String> getContent(final String entry) {
+ final List<String> returnedList = new ArrayList<String>();
+
+ for (final String country : this.EUROZONE) {
+ if (country.toLowerCase().startsWith(entry.toLowerCase())) {
+ returnedList.add(country);
+ }
+ }
+
+ return returnedList;
+ }
+ };
+
+ final TextAssist text = new TextAssist(shell, SWT.SINGLE | SWT.BORDER, contentProvider);
+ text.setLayoutData(new GridData(150, SWT.DEFAULT));
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/tipOfTheDay/TipOfTheDaySnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/tipOfTheDay/TipOfTheDaySnippet.java
new file mode 100644
index 0000000..b4b0d98
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/tipOfTheDay/TipOfTheDaySnippet.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * 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.tipOfTheDay;
+
+import java.util.Locale;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.tipOfTheDay.TipOfTheDay.TipStyle;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the Tip of the Day widget
+ *
+ */
+public class TipOfTheDaySnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+
+ Locale.setDefault(Locale.ENGLISH);
+
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setText("Tip of the Days snippet");
+ shell.setLayout(new FillLayout(SWT.VERTICAL));
+
+ final TipOfTheDay tip = new TipOfTheDay();
+ tip.addTip("This is the first tip<br/> " + "<b>This is the first tip</b> " + "<u>This is the first tip</u> " + "<i>This is the first tip</i> " + "This is the first tip " + "This is the first tip<br/>" + "This is the first tip "
+ + "This is the first tip");
+ tip.addTip("This is the second tip<br/> " + "<b>This is the second tip</b> " + "<u>This is the second tip</u> <br/>" + "<i>This is the second tip</i> " + "This is the second tip " + "This is the second tip <br/>" + "This is the second tip "
+ + "This is the second tip");
+
+ tip.addTip("This is the third tip<br/> " + "<b>This is the third tip</b> " + "<u>This is the third tip</u> <br/>" + "<i>This is the third tip</i> ");
+
+ final Button button1 = new Button(shell, SWT.PUSH);
+ button1.setText("Open Tip of the Day dialog (default style)");
+
+ button1.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ tip.setStyle(TipStyle.TWO_COLUMNS);
+ tip.open(shell);
+ }
+ });
+
+ final Button button2 = new Button(shell, SWT.PUSH);
+ button2.setText("Open Tip of the Day dialog (2 columns large)");
+
+ button2.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ tip.setStyle(TipStyle.TWO_COLUMNS_LARGE);
+ tip.open(shell);
+ }
+ });
+
+ final Button button3 = new Button(shell, SWT.PUSH);
+ button3.setText("Open Tip of the Day dialog (header)");
+
+ button3.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ tip.setStyle(TipStyle.HEADER);
+ tip.open(shell);
+ }
+ });
+
+ shell.pack();
+ shell.open();
+ SWTGraphicUtil.centerShell(shell);
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/titledSeparator/TitledSeparatorSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/titledSeparator/TitledSeparatorSnippet.java
new file mode 100644
index 0000000..4fe6e78
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/titledSeparator/TitledSeparatorSnippet.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * 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.titledSeparator;
+
+import org.eclipse.swt.SWT;
+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.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * This snippet demonstrates the TitledSeparator widget
+ *
+ */
+public class TitledSeparatorSnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(1, false));
+
+ final Image icon = new Image(display, TitledSeparatorSnippet.class.getClassLoader().getResourceAsStream("org/mihalis/opal/titledSeparator/user.png"));
+ final Font font = new Font(display, "Courier New", 18, SWT.BOLD | SWT.ITALIC);
+
+ // Default separator (no image, title aligned on the left)
+ final TitledSeparator sep1 = new TitledSeparator(shell, SWT.NONE);
+ sep1.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+ sep1.setText("Customer Info");
+
+ // Separator with image
+ final TitledSeparator sep2 = new TitledSeparator(shell, SWT.NONE);
+ sep2.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+ sep2.setText("Customer Info");
+ sep2.setImage(icon);
+
+ // Separator aligned on the right
+ final TitledSeparator sep3 = new TitledSeparator(shell, SWT.NONE);
+ sep3.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+ sep3.setText("Customer Info");
+ sep3.setAlignment(SWT.RIGHT);
+
+ // Custom font & text color
+ final TitledSeparator sep4 = new TitledSeparator(shell, SWT.NONE);
+ sep4.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
+ sep4.setText("Customized Color and Font");
+ sep4.setAlignment(SWT.CENTER);
+
+ sep4.setForeground(display.getSystemColor(SWT.COLOR_DARK_RED));
+ sep4.setFont(font);
+
+ shell.setSize(640, 350);
+ shell.pack();
+ shell.open();
+ SWTGraphicUtil.centerShell(shell);
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ icon.dispose();
+ font.dispose();
+
+ display.dispose();
+ }
+
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/titledSeparator/user.png b/org.mihalis.opal/src/test/java/org/mihalis/opal/titledSeparator/user.png
new file mode 100644
index 0000000..212cb86
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/titledSeparator/user.png
Binary files differ
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/transitionComposite/TransitionCompositeSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/transitionComposite/TransitionCompositeSnippet.java
new file mode 100644
index 0000000..4b4022c
--- /dev/null
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/transitionComposite/TransitionCompositeSnippet.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * 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.transitionComposite;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+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.Combo;
+import org.eclipse.swt.widgets.Composite;
+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;
+import org.mihalis.opal.utils.SWTGraphicUtil;
+
+/**
+ * A simple snipper for the TransitionComposite widget
+ *
+ */
+public class TransitionCompositeSnippet {
+
+ /**
+ * @param args
+ */
+ public static void main(final String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(2, false));
+
+ final Label changeTransition = new Label(shell, SWT.NONE);
+ changeTransition.setText("Select your transition");
+ changeTransition.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+
+ final Combo combo = new Combo(shell, SWT.READ_ONLY);
+ combo.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, true, false));
+ for (final TRANSITIONS t : TRANSITIONS.values()) {
+ combo.add(t.toString());
+ }
+
+ final TransitionComposite transitionComposite = new TransitionComposite(shell, SWT.NONE);
+ final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1);
+ gd.widthHint = 800;
+ gd.heightHint = 800;
+ transitionComposite.setLayoutData(gd);
+
+ combo.addSelectionListener(new SelectionAdapter() {
+
+ /**
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ transitionComposite.setTransition(TRANSITIONS.valueOf(combo.getText()));
+ }
+ });
+
+ combo.setText(TRANSITIONS.NONE.toString());
+ transitionComposite.setTransition(TRANSITIONS.NONE);
+
+ final String[] fileNames = { "org/mihalis/opal/imageSelector/images/Black Eyed Peas.jpg",//
+ "org/mihalis/opal/imageSelector/images/Coldplay.jpg",//
+ "org/mihalis/opal/imageSelector/images/Foo Fighters.jpg",//
+ "org/mihalis/opal/imageSelector/images/Gorillaz.jpg",//
+ "org/mihalis/opal/imageSelector/images/Green Day.jpg" };
+
+ for (int i = 1; i < 6; i++) {
+ final Composite c = new Composite(transitionComposite, SWT.BORDER);
+ c.setLayout(new GridLayout(4, false));
+
+ final Label lbl = new Label(c, SWT.NONE);
+ lbl.setText("You are on step #" + i);
+ lbl.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, true, true, 4, 1));
+
+ final Label img = new Label(c, SWT.NONE);
+ final Image image = new Image(display, TransitionCompositeSnippet.class.getClassLoader().getResourceAsStream(fileNames[i - 1]));
+ img.setImage(image);
+ final GridData imgGd = new GridData(GridData.CENTER, GridData.CENTER, true, true, 4, 1);
+ gd.widthHint = gd.heightHint = 600;
+ img.setLayoutData(imgGd);
+
+ img.addListener(SWT.Dispose, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ SWTGraphicUtil.safeDispose(image);
+ }
+ });
+
+ if (i != 1) {
+ final Button first = new Button(c, SWT.PUSH);
+ first.setText("Move to first step");
+ first.setLayoutData(new GridData(GridData.END, GridData.CENTER, true, false, i == 5 ? 3 : 1, 1));
+ first.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ transitionComposite.moveToFirst();
+ }
+ });
+
+ final Button back = new Button(c, SWT.PUSH);
+ back.setText("Move to previous step");
+ back.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, true, false));
+ back.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ transitionComposite.moveToPrevious();
+ }
+ });
+ }
+
+ if (i != 5) {
+
+ final Button next = new Button(c, SWT.PUSH);
+ next.setText("Move to next step");
+ next.setLayoutData(new GridData(GridData.END, GridData.CENTER, true, false, i == 1 ? 3 : 1, 1));
+ next.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ transitionComposite.moveToNext();
+ }
+ });
+
+ final Button last = new Button(c, SWT.PUSH);
+ last.setText("Move to last step");
+ last.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, true, false));
+ last.addListener(SWT.Selection, new Listener() {
+
+ @Override
+ public void handleEvent(final Event event) {
+ transitionComposite.moveToLast();
+ }
+ });
+
+ }
+ transitionComposite.addControl(c);
+
+ }
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+
+ }
+
+} \ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..e9d5b2b
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,111 @@
+<?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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.osbp.releng.maven</groupId>
+ <artifactId>org.eclipse.osbp.releng.maven.parent.tycho</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ <relativePath/>
+ </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>
+ <packaging>pom</packaging>
+
+ <url>${osbp.site.repository.url}</url>
+ <scm>
+ <url>${osbp.scm.url}</url>
+ <connection>${osbp.scm.connection}</connection>
+ <developerConnection>${osbp.scm.connection.dev}</developerConnection>
+ <tag>HEAD</tag>
+ </scm>
+ <distributionManagement>
+ <site>
+ <id>gh-pages</id>
+ <name>OSBP GitHub Pages</name>
+ <url>${distribution.site.url}</url>
+ </site>
+ </distributionManagement>
+
+ <properties>
+ <osbp.gitrepo.name>${project.groupId}</osbp.gitrepo.name>
+ </properties>
+
+ <modules>
+ <module>org.mihalis.opal</module>
+ <module>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi</module>
+ <module>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.feature</module>
+ <!-- <module>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.p2</module> -->
+ </modules>
+
+ <profiles>
+ <profile>
+ <id>build.p2</id>
+ <activation>
+ <property>
+ <name>osbp.build.p2</name>
+ </property>
+ </activation>
+ <modules>
+ <!-- <module>org.eclipse.osbp.fork.mihalis.opal.imageSelector.osgi.p2</module> -->
+ </modules>
+ </profile>
+ </profiles>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>target-platform-configuration</artifactId>
+ <version>${tycho-version}</version>
+ <configuration>
+ <resolver>p2</resolver>
+ <pomDependencies>consider</pomDependencies>
+ <environments>
+ <environment>
+ <os>win32</os>
+ <ws>win32</ws>
+ <arch>x86_64</arch>
+ </environment>
+ <environment>
+ <os>linux</os>
+ <ws>gtk</ws>
+ <arch>x86</arch>
+ </environment>
+ <environment>
+ <os>linux</os>
+ <ws>gtk</ws>
+ <arch>x86_64</arch>
+ </environment>
+ <environment>
+ <os>macosx</os>
+ <ws>cocoa</ws>
+ <arch>x86_64</arch>
+ </environment>
+ </environments>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+</project>

Back to the top