Hello!

To see the file structure, click on "tree".

Note that updates take place every 10 minutes, commits may not be seen immediately.
Uploaded initial version of image annotation project
authorlingutln <lingutln@localhost>
Mon, 7 Nov 2011 19:52:57 +0000 (19:52 +0000)
committerlingutln <lingutln@localhost>
Mon, 7 Nov 2011 19:52:57 +0000 (19:52 +0000)
svn path=/; revision=212

322 files changed:
Personnel/lingutln/.gitignore [new file with mode: 0644]
image_annotation/.gitignore [deleted file]
image_annotation/bin/BPTPlugin.plugin/bptplugin.jar [new file with mode: 0644]
image_annotation/bin/BPTPlugin.plugin/jbpt.dll [new file with mode: 0644]
image_annotation/bin/BPTPlugin.plugin/libjbpt.jnilib [new file with mode: 0644]
image_annotation/bin/BPTPlugin.plugin/plugin.xml [new file with mode: 0644]
image_annotation/bin/IGCPlugin.plugin/igcplugin.jar [new file with mode: 0644]
image_annotation/bin/IGCPlugin.plugin/jigc.dll [new file with mode: 0644]
image_annotation/bin/IGCPlugin.plugin/libjigc.jnilib [new file with mode: 0644]
image_annotation/bin/IGCPlugin.plugin/plugin.xml [new file with mode: 0644]
image_annotation/bin/SIOXPlugin.plugin/plugin.xml [new file with mode: 0644]
image_annotation/bin/SIOXPlugin.plugin/sioxapi.jar [new file with mode: 0644]
image_annotation/bin/SIOXPlugin.plugin/sioxplugin.jar [new file with mode: 0644]
image_annotation/bin/SRGPlugin.plugin/jsrg.dll [new file with mode: 0644]
image_annotation/bin/SRGPlugin.plugin/libjsrg.jnilib [new file with mode: 0644]
image_annotation/bin/SRGPlugin.plugin/plugin.xml [new file with mode: 0644]
image_annotation/bin/SRGPlugin.plugin/srgplugin.jar [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppPrefs$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppPrefs$2.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppPrefs$Keys.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppPrefs$SupportedTypes.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppPrefs.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppPrefsManager.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppRecentFiles.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$2.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$EmptyAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppStatus.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppWindow$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppWindow$2.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppWindow$3.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppWindow$ImageObserver.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/AppWindow.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/Application.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/EvaluatorRegistry.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/Main.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/PainterRegistry.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/SegmenterRegistry.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/AboutAction$AboutBox.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/AboutAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/ActionManager.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/AppAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/ConfigureSegmenterAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/ConfiguredAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/CopyAction$ImageSelection.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/CopyAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/ExitAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/ExportImageMapAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/ExportTransparentPNGAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/ExportViewAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction$HelpBox$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction$HelpBox.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/HoverAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager$HoverListener.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/IHoverAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/NextAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/OpenAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/OpenExperimentAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/OpenRecentAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/PreferencesAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/PreviousAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/PrintAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/RedoAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/SaveAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/SaveAsAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/SelectSegmenterAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/SimpleFileFilter.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/actions/UndoAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/controllers/AnnotationTool.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/controllers/MouseMotionAdapter.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$2.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$3.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$4.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$Result.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/dialogs/PrefsDialog$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/dialogs/PrefsDialog.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/event/ContextChangeListener.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/event/ContextChangedEvent.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/event/StateEvent.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/event/StateListener.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/event/TickerEvent.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/event/TickerListener.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/event/TimeoutEvent.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/event/TimeoutListener.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/exp/Experiment.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentFactory.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentManager.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentResults.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/exp/FormatException.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/exp/StorageSelection.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/exp/Task.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/AreaShape.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/ExportException.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/Exporter.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/HtmlTag.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/ImageMap.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/MapArea.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$BrightenForeground.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$DarkenBackground.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$OutlineObject.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/export/imagemap/template.html [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/recent/RecentFiles$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/recent/RecentFiles.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/recent/RecentFilesEvent.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/recent/RecentFilesListener.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/EvaluationListener.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$2.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$3.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$ButtonType.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$2.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$3.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$4.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$EventHandler.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$RobustSegmenterProxy.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$Tool.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$ToolAction.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$2.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$3.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/BrushControl$ScaleChangeListener.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/BrushControl.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/ColorSelector$ControlListener.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/ColorSelector.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/ImageMenuManager.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$1.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$2.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$3.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$4.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$State.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer.class [new file with mode: 0644]
image_annotation/bin/ie/dcu/apps/ist/widgets/Ticker.class [new file with mode: 0644]
image_annotation/build.xml [new file with mode: 0644]
image_annotation/lib/._swt-cocoa-32.jar [new file with mode: 0644]
image_annotation/lib/._swt-cocoa-64.jar [new file with mode: 0644]
image_annotation/lib/.classpath [new file with mode: 0644]
image_annotation/lib/.project [new file with mode: 0644]
image_annotation/lib/istapi-doc.zip [new file with mode: 0644]
image_annotation/lib/istapi-src.jar [new file with mode: 0644]
image_annotation/lib/istapi.jar [new file with mode: 0644]
image_annotation/lib/jface.jar [new file with mode: 0644]
image_annotation/lib/swt-cocoa-32.jar [new file with mode: 0644]
image_annotation/lib/swt-cocoa-64.jar [new file with mode: 0644]
image_annotation/lib/swt-gtk-64.jar [new file with mode: 0644]
image_annotation/lib/swt-gtk.jar [new file with mode: 0644]
image_annotation/lib/swt-win.jar [new file with mode: 0644]
image_annotation/plugins/BPTPlugin.plugin/bptplugin.jar [new file with mode: 0644]
image_annotation/plugins/BPTPlugin.plugin/jbpt.dll [new file with mode: 0644]
image_annotation/plugins/BPTPlugin.plugin/libjbpt.jnilib [new file with mode: 0644]
image_annotation/plugins/BPTPlugin.plugin/plugin.xml [new file with mode: 0644]
image_annotation/plugins/IGCPlugin.plugin/igcplugin.jar [new file with mode: 0644]
image_annotation/plugins/IGCPlugin.plugin/jigc.dll [new file with mode: 0644]
image_annotation/plugins/IGCPlugin.plugin/libjigc.jnilib [new file with mode: 0644]
image_annotation/plugins/IGCPlugin.plugin/plugin.xml [new file with mode: 0644]
image_annotation/plugins/SIOXPlugin.plugin/plugin.xml [new file with mode: 0644]
image_annotation/plugins/SIOXPlugin.plugin/sioxapi.jar [new file with mode: 0644]
image_annotation/plugins/SIOXPlugin.plugin/sioxplugin.jar [new file with mode: 0644]
image_annotation/plugins/SRGPlugin.plugin/jsrg.dll [new file with mode: 0644]
image_annotation/plugins/SRGPlugin.plugin/libjsrg.jnilib [new file with mode: 0644]
image_annotation/plugins/SRGPlugin.plugin/plugin.xml [new file with mode: 0644]
image_annotation/plugins/SRGPlugin.plugin/srgplugin.jar [new file with mode: 0644]
image_annotation/resources/ant/lib/ant-deb.jar [new file with mode: 0644]
image_annotation/resources/ant/lib/ant-gzip2.jar [new file with mode: 0644]
image_annotation/resources/ant/lib/ant-passwd-task.jar [new file with mode: 0644]
image_annotation/resources/ant/lib/ant-swt-identify.jar [new file with mode: 0644]
image_annotation/resources/ant/lib/jsmoothgen-ant.jar [new file with mode: 0644]
image_annotation/resources/ant/lib/standalone-compiler.jar [new file with mode: 0644]
image_annotation/resources/ant/properties [new file with mode: 0644]
image_annotation/resources/config/actions.mac.properties [new file with mode: 0644]
image_annotation/resources/config/actions.properties [new file with mode: 0644]
image_annotation/resources/config/application.mac.properties [new file with mode: 0644]
image_annotation/resources/config/application.properties [new file with mode: 0644]
image_annotation/resources/config/view.properties [new file with mode: 0644]
image_annotation/resources/doc/help.html [new file with mode: 0644]
image_annotation/resources/icons/about-box.png [new file with mode: 0644]
image_annotation/resources/icons/about.png [new file with mode: 0644]
image_annotation/resources/icons/application.png [new file with mode: 0644]
image_annotation/resources/icons/apply.png [new file with mode: 0644]
image_annotation/resources/icons/auto.png [new file with mode: 0644]
image_annotation/resources/icons/background.png [new file with mode: 0644]
image_annotation/resources/icons/brush.png [new file with mode: 0644]
image_annotation/resources/icons/clear.png [new file with mode: 0644]
image_annotation/resources/icons/close.png [new file with mode: 0644]
image_annotation/resources/icons/copy.png [new file with mode: 0644]
image_annotation/resources/icons/dialog-error.png [new file with mode: 0644]
image_annotation/resources/icons/dialog-information.png [new file with mode: 0644]
image_annotation/resources/icons/dialog-warning.png [new file with mode: 0644]
image_annotation/resources/icons/exit.png [new file with mode: 0644]
image_annotation/resources/icons/experiment.png [new file with mode: 0644]
image_annotation/resources/icons/export.png [new file with mode: 0644]
image_annotation/resources/icons/foreground.png [new file with mode: 0644]
image_annotation/resources/icons/help.png [new file with mode: 0644]
image_annotation/resources/icons/html.png [new file with mode: 0644]
image_annotation/resources/icons/icon-16.png [new file with mode: 0644]
image_annotation/resources/icons/icon-24.png [new file with mode: 0644]
image_annotation/resources/icons/icon-32.png [new file with mode: 0644]
image_annotation/resources/icons/icon-48.png [new file with mode: 0644]
image_annotation/resources/icons/image.png [new file with mode: 0644]
image_annotation/resources/icons/next.png [new file with mode: 0644]
image_annotation/resources/icons/open-recent.png [new file with mode: 0644]
image_annotation/resources/icons/open.png [new file with mode: 0644]
image_annotation/resources/icons/preferences.png [new file with mode: 0644]
image_annotation/resources/icons/previous.png [new file with mode: 0644]
image_annotation/resources/icons/print.png [new file with mode: 0644]
image_annotation/resources/icons/redo.png [new file with mode: 0644]
image_annotation/resources/icons/refresh.png [new file with mode: 0644]
image_annotation/resources/icons/reset.png [new file with mode: 0644]
image_annotation/resources/icons/run.png [new file with mode: 0644]
image_annotation/resources/icons/save-as.png [new file with mode: 0644]
image_annotation/resources/icons/save.png [new file with mode: 0644]
image_annotation/resources/icons/undo.png [new file with mode: 0644]
image_annotation/resources/icons/view.png [new file with mode: 0644]
image_annotation/resources/icons/zoom-best-fit.png [new file with mode: 0644]
image_annotation/resources/icons/zoom-in.png [new file with mode: 0644]
image_annotation/resources/icons/zoom-original.png [new file with mode: 0644]
image_annotation/resources/icons/zoom-out.png [new file with mode: 0644]
image_annotation/resources/plaf/debian/changelog [new file with mode: 0644]
image_annotation/resources/plaf/debian/copyright [new file with mode: 0644]
image_annotation/resources/plaf/debian/desktop [new file with mode: 0644]
image_annotation/resources/plaf/debian/ist [new file with mode: 0644]
image_annotation/resources/plaf/debian/ist.1 [new file with mode: 0644]
image_annotation/resources/plaf/debian/postinst [new file with mode: 0644]
image_annotation/resources/plaf/debian/postrm [new file with mode: 0644]
image_annotation/resources/plaf/linux/ist [new file with mode: 0644]
image_annotation/resources/plaf/mac/Info.plist [new file with mode: 0644]
image_annotation/resources/plaf/mac/PkgInfo [new file with mode: 0644]
image_annotation/resources/plaf/mac/icon.icns [new file with mode: 0644]
image_annotation/resources/plaf/mac/ist [new file with mode: 0644]
image_annotation/resources/plaf/windows/application.ico [new file with mode: 0644]
image_annotation/resources/plaf/windows/install.xml [new file with mode: 0644]
image_annotation/resources/plaf/windows/installer.ico [new file with mode: 0644]
image_annotation/resources/plaf/windows/installer.jsmooth [new file with mode: 0644]
image_annotation/resources/plaf/windows/ist.jsmooth [new file with mode: 0644]
image_annotation/resources/plaf/windows/shortcuts.xml [new file with mode: 0644]
image_annotation/resources/plaf/windows/skeletons/windowed-wrapper/description.skel [new file with mode: 0644]
image_annotation/resources/plaf/windows/skeletons/windowed-wrapper/jwrap.exe [new file with mode: 0755]
image_annotation/src/ie/dcu/apps/ist/AppPrefs.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/AppPrefsManager.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/AppRecentFiles.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/AppRecentMenu.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/AppStatus.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/AppWindow.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/Application.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/EvaluatorRegistry.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/Main.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/PainterRegistry.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/SegmenterRegistry.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/AboutAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/ActionManager.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/AppAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/ConfigureSegmenterAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/ConfiguredAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/CopyAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/ExitAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/ExportImageMapAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/ExportTransparentPNGAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/ExportViewAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/HelpAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/HoverAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/HoverMenuManager.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/IHoverAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/NextAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/OpenAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/OpenExperimentAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/OpenRecentAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/PreferencesAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/PreviousAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/PrintAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/RedoAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/SaveAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/SaveAsAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/SelectSegmenterAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/actions/UndoAction.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/controllers/AnnotationTool.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/controllers/MouseMotionAdapter.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/dialogs/ExportDialog.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/dialogs/PrefsDialog.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/event/ContextChangeListener.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/event/ContextChangedEvent.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/event/StateEvent.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/event/StateListener.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/event/TickerEvent.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/event/TickerListener.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/event/TimeoutEvent.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/event/TimeoutListener.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/exp/Experiment.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/exp/ExperimentFactory.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/exp/ExperimentManager.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/exp/ExperimentResults.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/exp/FormatException.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/exp/StorageSelection.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/exp/Task.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/export/imagemap/AreaShape.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/export/imagemap/ExportException.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/export/imagemap/Exporter.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/export/imagemap/HtmlTag.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/export/imagemap/ImageMap.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/export/imagemap/MapArea.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/export/imagemap/RolloverEffect.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/export/imagemap/template.html [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/recent/RecentFiles.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/recent/RecentFilesEvent.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/recent/RecentFilesListener.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/views/ExperimentPanel.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/views/SegmentationView.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/widgets/AnnotatedImageControl.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/widgets/BrushControl.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/widgets/ColorSelector.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/widgets/ImageMenuManager.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/widgets/SwtTimer.java [new file with mode: 0644]
image_annotation/src/ie/dcu/apps/ist/widgets/Ticker.java [new file with mode: 0644]

diff --git a/Personnel/lingutln/.gitignore b/Personnel/lingutln/.gitignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/image_annotation/.gitignore b/image_annotation/.gitignore
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/image_annotation/bin/BPTPlugin.plugin/bptplugin.jar b/image_annotation/bin/BPTPlugin.plugin/bptplugin.jar
new file mode 100644 (file)
index 0000000..d4025cf
Binary files /dev/null and b/image_annotation/bin/BPTPlugin.plugin/bptplugin.jar differ
diff --git a/image_annotation/bin/BPTPlugin.plugin/jbpt.dll b/image_annotation/bin/BPTPlugin.plugin/jbpt.dll
new file mode 100644 (file)
index 0000000..d12f777
Binary files /dev/null and b/image_annotation/bin/BPTPlugin.plugin/jbpt.dll differ
diff --git a/image_annotation/bin/BPTPlugin.plugin/libjbpt.jnilib b/image_annotation/bin/BPTPlugin.plugin/libjbpt.jnilib
new file mode 100644 (file)
index 0000000..77039d7
Binary files /dev/null and b/image_annotation/bin/BPTPlugin.plugin/libjbpt.jnilib differ
diff --git a/image_annotation/bin/BPTPlugin.plugin/plugin.xml b/image_annotation/bin/BPTPlugin.plugin/plugin.xml
new file mode 100644 (file)
index 0000000..4ae529d
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<plugin>
+       <meta name="name" value="BPT Plugin" />
+       <meta name="description" value="Binary Partition Tree Plugin" />
+       <meta name="vendor" value="Dublin City University" />
+       <meta name="author" value="Kevin McGuinness" />
+       <meta name="email" value="kevin.mcguinness@gmail.com" />
+       <meta name="segmenter" value="ie.dcu.segment.algorithm.BptSegmenter" /> 
+       <jar file="bptplugin.jar" />
+</plugin>
diff --git a/image_annotation/bin/IGCPlugin.plugin/igcplugin.jar b/image_annotation/bin/IGCPlugin.plugin/igcplugin.jar
new file mode 100644 (file)
index 0000000..c85393b
Binary files /dev/null and b/image_annotation/bin/IGCPlugin.plugin/igcplugin.jar differ
diff --git a/image_annotation/bin/IGCPlugin.plugin/jigc.dll b/image_annotation/bin/IGCPlugin.plugin/jigc.dll
new file mode 100644 (file)
index 0000000..b4ee98c
Binary files /dev/null and b/image_annotation/bin/IGCPlugin.plugin/jigc.dll differ
diff --git a/image_annotation/bin/IGCPlugin.plugin/libjigc.jnilib b/image_annotation/bin/IGCPlugin.plugin/libjigc.jnilib
new file mode 100644 (file)
index 0000000..6ff9817
Binary files /dev/null and b/image_annotation/bin/IGCPlugin.plugin/libjigc.jnilib differ
diff --git a/image_annotation/bin/IGCPlugin.plugin/plugin.xml b/image_annotation/bin/IGCPlugin.plugin/plugin.xml
new file mode 100644 (file)
index 0000000..2b7ae2e
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<plugin>
+       <meta name="name" value="IGC Plugin" />
+       <meta name="description" value="Interactive Graph Cuts Plugin" />
+       <meta name="vendor" value="Dublin City University" />
+       <meta name="author" value="Kevin McGuinness" />
+       <meta name="email" value="kevin.mcguinness@gmail.com" />
+       <meta name="segmenter" value="ie.dcu.segment.algorithm.IgcSegmenter" /> 
+       <jar file="igcplugin.jar" />
+</plugin>
diff --git a/image_annotation/bin/SIOXPlugin.plugin/plugin.xml b/image_annotation/bin/SIOXPlugin.plugin/plugin.xml
new file mode 100644 (file)
index 0000000..623ad7b
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<plugin>
+       <meta name="name" value="SIOX Plugin" />
+       <meta name="description" value="Simple Interactive Object Extraction Plugin" />
+       <meta name="vendor" value="Dublin City University" />
+       <meta name="author" value="Kevin McGuinness" />
+       <meta name="email" value="kevin.mcguinness@gmail.com" />
+       <meta name="segmenter" value="ie.dcu.segment.algorithm.SioxSegmenter" />        
+       <jar file="sioxplugin.jar" />
+       <jar file="sioxapi.jar" />
+</plugin>
diff --git a/image_annotation/bin/SIOXPlugin.plugin/sioxapi.jar b/image_annotation/bin/SIOXPlugin.plugin/sioxapi.jar
new file mode 100644 (file)
index 0000000..4c121b2
Binary files /dev/null and b/image_annotation/bin/SIOXPlugin.plugin/sioxapi.jar differ
diff --git a/image_annotation/bin/SIOXPlugin.plugin/sioxplugin.jar b/image_annotation/bin/SIOXPlugin.plugin/sioxplugin.jar
new file mode 100644 (file)
index 0000000..31f959a
Binary files /dev/null and b/image_annotation/bin/SIOXPlugin.plugin/sioxplugin.jar differ
diff --git a/image_annotation/bin/SRGPlugin.plugin/jsrg.dll b/image_annotation/bin/SRGPlugin.plugin/jsrg.dll
new file mode 100644 (file)
index 0000000..c381fae
Binary files /dev/null and b/image_annotation/bin/SRGPlugin.plugin/jsrg.dll differ
diff --git a/image_annotation/bin/SRGPlugin.plugin/libjsrg.jnilib b/image_annotation/bin/SRGPlugin.plugin/libjsrg.jnilib
new file mode 100644 (file)
index 0000000..46427e8
Binary files /dev/null and b/image_annotation/bin/SRGPlugin.plugin/libjsrg.jnilib differ
diff --git a/image_annotation/bin/SRGPlugin.plugin/plugin.xml b/image_annotation/bin/SRGPlugin.plugin/plugin.xml
new file mode 100644 (file)
index 0000000..4061f98
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<plugin>
+       <meta name="name" value="SRG Plugin" />
+       <meta name="description" value="Seeded Region Growing Plugin" />
+       <meta name="vendor" value="Dublin City University" />
+       <meta name="author" value="Kevin McGuinness" />
+       <meta name="email" value="kevin.mcguinness@gmail.com" />
+       <meta name="segmenter" value="ie.dcu.segment.algorithm.SrgSegmenter" /> 
+       <jar file="srgplugin.jar" />
+</plugin>
diff --git a/image_annotation/bin/SRGPlugin.plugin/srgplugin.jar b/image_annotation/bin/SRGPlugin.plugin/srgplugin.jar
new file mode 100644 (file)
index 0000000..c888c62
Binary files /dev/null and b/image_annotation/bin/SRGPlugin.plugin/srgplugin.jar differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$1.class b/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$1.class
new file mode 100644 (file)
index 0000000..3e1e74f
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$2.class b/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$2.class
new file mode 100644 (file)
index 0000000..1356599
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$2.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$Keys.class b/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$Keys.class
new file mode 100644 (file)
index 0000000..13fa3dc
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$Keys.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$SupportedTypes.class b/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$SupportedTypes.class
new file mode 100644 (file)
index 0000000..337ba2e
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppPrefs$SupportedTypes.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppPrefs.class b/image_annotation/bin/ie/dcu/apps/ist/AppPrefs.class
new file mode 100644 (file)
index 0000000..3eb1f25
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppPrefs.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppPrefsManager.class b/image_annotation/bin/ie/dcu/apps/ist/AppPrefsManager.class
new file mode 100644 (file)
index 0000000..651127c
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppPrefsManager.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppRecentFiles.class b/image_annotation/bin/ie/dcu/apps/ist/AppRecentFiles.class
new file mode 100644 (file)
index 0000000..a8f73c5
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppRecentFiles.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$1.class b/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$1.class
new file mode 100644 (file)
index 0000000..9c6f352
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$2.class b/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$2.class
new file mode 100644 (file)
index 0000000..7960862
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$2.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$EmptyAction.class b/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$EmptyAction.class
new file mode 100644 (file)
index 0000000..75a1d08
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu$EmptyAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu.class b/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu.class
new file mode 100644 (file)
index 0000000..c993dae
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppRecentMenu.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppStatus.class b/image_annotation/bin/ie/dcu/apps/ist/AppStatus.class
new file mode 100644 (file)
index 0000000..c877538
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppStatus.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppWindow$1.class b/image_annotation/bin/ie/dcu/apps/ist/AppWindow$1.class
new file mode 100644 (file)
index 0000000..4bdc205
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppWindow$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppWindow$2.class b/image_annotation/bin/ie/dcu/apps/ist/AppWindow$2.class
new file mode 100644 (file)
index 0000000..21e30e0
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppWindow$2.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppWindow$3.class b/image_annotation/bin/ie/dcu/apps/ist/AppWindow$3.class
new file mode 100644 (file)
index 0000000..0b7745f
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppWindow$3.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppWindow$ImageObserver.class b/image_annotation/bin/ie/dcu/apps/ist/AppWindow$ImageObserver.class
new file mode 100644 (file)
index 0000000..dfc6a8b
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppWindow$ImageObserver.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/AppWindow.class b/image_annotation/bin/ie/dcu/apps/ist/AppWindow.class
new file mode 100644 (file)
index 0000000..23c945c
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/AppWindow.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/Application.class b/image_annotation/bin/ie/dcu/apps/ist/Application.class
new file mode 100644 (file)
index 0000000..c1be587
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/Application.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/EvaluatorRegistry.class b/image_annotation/bin/ie/dcu/apps/ist/EvaluatorRegistry.class
new file mode 100644 (file)
index 0000000..55365d3
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/EvaluatorRegistry.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/Main.class b/image_annotation/bin/ie/dcu/apps/ist/Main.class
new file mode 100644 (file)
index 0000000..623c934
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/Main.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/PainterRegistry.class b/image_annotation/bin/ie/dcu/apps/ist/PainterRegistry.class
new file mode 100644 (file)
index 0000000..f257b72
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/PainterRegistry.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/SegmenterRegistry.class b/image_annotation/bin/ie/dcu/apps/ist/SegmenterRegistry.class
new file mode 100644 (file)
index 0000000..a4d4fde
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/SegmenterRegistry.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/AboutAction$AboutBox.class b/image_annotation/bin/ie/dcu/apps/ist/actions/AboutAction$AboutBox.class
new file mode 100644 (file)
index 0000000..77e8e60
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/AboutAction$AboutBox.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/AboutAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/AboutAction.class
new file mode 100644 (file)
index 0000000..c31de41
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/AboutAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/ActionManager.class b/image_annotation/bin/ie/dcu/apps/ist/actions/ActionManager.class
new file mode 100644 (file)
index 0000000..032267e
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/ActionManager.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/AppAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/AppAction.class
new file mode 100644 (file)
index 0000000..15ee7a5
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/AppAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/ConfigureSegmenterAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/ConfigureSegmenterAction.class
new file mode 100644 (file)
index 0000000..3050adf
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/ConfigureSegmenterAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/ConfiguredAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/ConfiguredAction.class
new file mode 100644 (file)
index 0000000..80e3be7
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/ConfiguredAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/CopyAction$ImageSelection.class b/image_annotation/bin/ie/dcu/apps/ist/actions/CopyAction$ImageSelection.class
new file mode 100644 (file)
index 0000000..7f13bb1
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/CopyAction$ImageSelection.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/CopyAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/CopyAction.class
new file mode 100644 (file)
index 0000000..550bd90
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/CopyAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/ExitAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/ExitAction.class
new file mode 100644 (file)
index 0000000..d87ce2b
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/ExitAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/ExportImageMapAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/ExportImageMapAction.class
new file mode 100644 (file)
index 0000000..8f0224d
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/ExportImageMapAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/ExportTransparentPNGAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/ExportTransparentPNGAction.class
new file mode 100644 (file)
index 0000000..c4d82e4
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/ExportTransparentPNGAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/ExportViewAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/ExportViewAction.class
new file mode 100644 (file)
index 0000000..a74bd89
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/ExportViewAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction$HelpBox$1.class b/image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction$HelpBox$1.class
new file mode 100644 (file)
index 0000000..43e3dce
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction$HelpBox$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction$HelpBox.class b/image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction$HelpBox.class
new file mode 100644 (file)
index 0000000..d001d7d
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction$HelpBox.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction.class
new file mode 100644 (file)
index 0000000..dd7b846
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/HelpAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/HoverAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/HoverAction.class
new file mode 100644 (file)
index 0000000..de62c98
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/HoverAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager$1.class b/image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager$1.class
new file mode 100644 (file)
index 0000000..e04e53b
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager$HoverListener.class b/image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager$HoverListener.class
new file mode 100644 (file)
index 0000000..5e058f1
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager$HoverListener.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager.class b/image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager.class
new file mode 100644 (file)
index 0000000..c27e1b4
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/HoverMenuManager.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/IHoverAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/IHoverAction.class
new file mode 100644 (file)
index 0000000..f57a6ea
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/IHoverAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/NextAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/NextAction.class
new file mode 100644 (file)
index 0000000..1c4d433
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/NextAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/OpenAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/OpenAction.class
new file mode 100644 (file)
index 0000000..ba68616
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/OpenAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/OpenExperimentAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/OpenExperimentAction.class
new file mode 100644 (file)
index 0000000..4ec3ca9
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/OpenExperimentAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/OpenRecentAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/OpenRecentAction.class
new file mode 100644 (file)
index 0000000..115347d
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/OpenRecentAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/PreferencesAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/PreferencesAction.class
new file mode 100644 (file)
index 0000000..9937282
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/PreferencesAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/PreviousAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/PreviousAction.class
new file mode 100644 (file)
index 0000000..492d688
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/PreviousAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/PrintAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/PrintAction.class
new file mode 100644 (file)
index 0000000..818b060
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/PrintAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/RedoAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/RedoAction.class
new file mode 100644 (file)
index 0000000..e6c3d2c
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/RedoAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/SaveAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/SaveAction.class
new file mode 100644 (file)
index 0000000..127a834
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/SaveAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/SaveAsAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/SaveAsAction.class
new file mode 100644 (file)
index 0000000..f209d77
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/SaveAsAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/SelectSegmenterAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/SelectSegmenterAction.class
new file mode 100644 (file)
index 0000000..a7c8283
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/SelectSegmenterAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/SimpleFileFilter.class b/image_annotation/bin/ie/dcu/apps/ist/actions/SimpleFileFilter.class
new file mode 100644 (file)
index 0000000..7c65f92
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/SimpleFileFilter.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/actions/UndoAction.class b/image_annotation/bin/ie/dcu/apps/ist/actions/UndoAction.class
new file mode 100644 (file)
index 0000000..1b88f46
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/actions/UndoAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/controllers/AnnotationTool.class b/image_annotation/bin/ie/dcu/apps/ist/controllers/AnnotationTool.class
new file mode 100644 (file)
index 0000000..ffe0a3b
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/controllers/AnnotationTool.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/controllers/MouseMotionAdapter.class b/image_annotation/bin/ie/dcu/apps/ist/controllers/MouseMotionAdapter.class
new file mode 100644 (file)
index 0000000..b4e6a7a
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/controllers/MouseMotionAdapter.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$1.class b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$1.class
new file mode 100644 (file)
index 0000000..5998e37
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$2.class b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$2.class
new file mode 100644 (file)
index 0000000..95be366
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$2.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$3.class b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$3.class
new file mode 100644 (file)
index 0000000..416ae9b
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$3.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$4.class b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$4.class
new file mode 100644 (file)
index 0000000..672bde2
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$4.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$Result.class b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$Result.class
new file mode 100644 (file)
index 0000000..69e7e9b
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog$Result.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog.class b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog.class
new file mode 100644 (file)
index 0000000..f91e5fb
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/dialogs/ExportDialog.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/dialogs/PrefsDialog$1.class b/image_annotation/bin/ie/dcu/apps/ist/dialogs/PrefsDialog$1.class
new file mode 100644 (file)
index 0000000..383ee6c
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/dialogs/PrefsDialog$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/dialogs/PrefsDialog.class b/image_annotation/bin/ie/dcu/apps/ist/dialogs/PrefsDialog.class
new file mode 100644 (file)
index 0000000..1a6d789
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/dialogs/PrefsDialog.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/event/ContextChangeListener.class b/image_annotation/bin/ie/dcu/apps/ist/event/ContextChangeListener.class
new file mode 100644 (file)
index 0000000..8452af6
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/event/ContextChangeListener.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/event/ContextChangedEvent.class b/image_annotation/bin/ie/dcu/apps/ist/event/ContextChangedEvent.class
new file mode 100644 (file)
index 0000000..627034f
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/event/ContextChangedEvent.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/event/StateEvent.class b/image_annotation/bin/ie/dcu/apps/ist/event/StateEvent.class
new file mode 100644 (file)
index 0000000..47ed701
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/event/StateEvent.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/event/StateListener.class b/image_annotation/bin/ie/dcu/apps/ist/event/StateListener.class
new file mode 100644 (file)
index 0000000..c4aaae3
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/event/StateListener.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/event/TickerEvent.class b/image_annotation/bin/ie/dcu/apps/ist/event/TickerEvent.class
new file mode 100644 (file)
index 0000000..0b9daff
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/event/TickerEvent.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/event/TickerListener.class b/image_annotation/bin/ie/dcu/apps/ist/event/TickerListener.class
new file mode 100644 (file)
index 0000000..45511b3
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/event/TickerListener.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/event/TimeoutEvent.class b/image_annotation/bin/ie/dcu/apps/ist/event/TimeoutEvent.class
new file mode 100644 (file)
index 0000000..f8a1313
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/event/TimeoutEvent.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/event/TimeoutListener.class b/image_annotation/bin/ie/dcu/apps/ist/event/TimeoutListener.class
new file mode 100644 (file)
index 0000000..4b01d67
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/event/TimeoutListener.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/exp/Experiment.class b/image_annotation/bin/ie/dcu/apps/ist/exp/Experiment.class
new file mode 100644 (file)
index 0000000..89c237e
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/exp/Experiment.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentFactory.class b/image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentFactory.class
new file mode 100644 (file)
index 0000000..91d7718
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentFactory.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentManager.class b/image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentManager.class
new file mode 100644 (file)
index 0000000..d9f713a
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentManager.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentResults.class b/image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentResults.class
new file mode 100644 (file)
index 0000000..4d70115
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/exp/ExperimentResults.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/exp/FormatException.class b/image_annotation/bin/ie/dcu/apps/ist/exp/FormatException.class
new file mode 100644 (file)
index 0000000..283a99a
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/exp/FormatException.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/exp/StorageSelection.class b/image_annotation/bin/ie/dcu/apps/ist/exp/StorageSelection.class
new file mode 100644 (file)
index 0000000..ade3ece
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/exp/StorageSelection.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/exp/Task.class b/image_annotation/bin/ie/dcu/apps/ist/exp/Task.class
new file mode 100644 (file)
index 0000000..24bbccd
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/exp/Task.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/AreaShape.class b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/AreaShape.class
new file mode 100644 (file)
index 0000000..2b78c0b
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/AreaShape.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/ExportException.class b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/ExportException.class
new file mode 100644 (file)
index 0000000..c0070b3
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/ExportException.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/Exporter.class b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/Exporter.class
new file mode 100644 (file)
index 0000000..65b56fb
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/Exporter.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/HtmlTag.class b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/HtmlTag.class
new file mode 100644 (file)
index 0000000..fcbd5f6
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/HtmlTag.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/ImageMap.class b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/ImageMap.class
new file mode 100644 (file)
index 0000000..712d59f
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/ImageMap.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/MapArea.class b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/MapArea.class
new file mode 100644 (file)
index 0000000..0988502
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/MapArea.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$BrightenForeground.class b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$BrightenForeground.class
new file mode 100644 (file)
index 0000000..36e78d2
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$BrightenForeground.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$DarkenBackground.class b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$DarkenBackground.class
new file mode 100644 (file)
index 0000000..ba2d35a
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$DarkenBackground.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$OutlineObject.class b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$OutlineObject.class
new file mode 100644 (file)
index 0000000..17576cd
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect$OutlineObject.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect.class b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect.class
new file mode 100644 (file)
index 0000000..bfeb640
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/RolloverEffect.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/template.html b/image_annotation/bin/ie/dcu/apps/ist/export/imagemap/template.html
new file mode 100644 (file)
index 0000000..159d2a1
--- /dev/null
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+    <!-- Generated using the CDVP Interactive Segmentation Tool -->
+    <meta http-equiv="Content-type" 
+          content="text/html; charset=utf-8"/>
+    <meta name="Generator" 
+          content="Interactive Segmentation Tool"/>
+    
+    <title>${page-title}</title>
+    
+    <script type="text/javascript" language="javascript">
+               
+${preloads}
+               
+        function rollover(docElem, image) {
+            docElem.src = image.src
+            return true
+        }
+        
+    </script>
+  
+</head>
+<body>
+    <!-- Image -->
+    <img name="${image-name}"
+         src="${image-href}" 
+         usemap="#${map-name}" 
+         alt="${image-alt}"
+         title="${image-alt}"/>
+    
+    <!-- Image map -->
+    <map name="${map-name}" id="${map-name}">
+${contents}
+    </map>
+</body>
+</html>
\ No newline at end of file
diff --git a/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFiles$1.class b/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFiles$1.class
new file mode 100644 (file)
index 0000000..2404137
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFiles$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFiles.class b/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFiles.class
new file mode 100644 (file)
index 0000000..bf2d162
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFiles.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFilesEvent.class b/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFilesEvent.class
new file mode 100644 (file)
index 0000000..e1b6618
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFilesEvent.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFilesListener.class b/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFilesListener.class
new file mode 100644 (file)
index 0000000..b1b7d91
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/recent/RecentFilesListener.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/EvaluationListener.class b/image_annotation/bin/ie/dcu/apps/ist/views/EvaluationListener.class
new file mode 100644 (file)
index 0000000..6c4a328
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/EvaluationListener.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$1.class b/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$1.class
new file mode 100644 (file)
index 0000000..b068920
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$2.class b/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$2.class
new file mode 100644 (file)
index 0000000..159a197
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$2.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$3.class b/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$3.class
new file mode 100644 (file)
index 0000000..ada5e53
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$3.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$ButtonType.class b/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$ButtonType.class
new file mode 100644 (file)
index 0000000..34c12e3
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel$ButtonType.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel.class b/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel.class
new file mode 100644 (file)
index 0000000..c1696f1
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/ExperimentPanel.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$1.class b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$1.class
new file mode 100644 (file)
index 0000000..bf56677
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$2.class b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$2.class
new file mode 100644 (file)
index 0000000..49f29da
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$2.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$3.class b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$3.class
new file mode 100644 (file)
index 0000000..dd3a873
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$3.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$4.class b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$4.class
new file mode 100644 (file)
index 0000000..3b8e206
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$4.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$EventHandler.class b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$EventHandler.class
new file mode 100644 (file)
index 0000000..7038114
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$EventHandler.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$RobustSegmenterProxy.class b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$RobustSegmenterProxy.class
new file mode 100644 (file)
index 0000000..f37c2f5
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$RobustSegmenterProxy.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$Tool.class b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$Tool.class
new file mode 100644 (file)
index 0000000..c68788c
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$Tool.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$ToolAction.class b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$ToolAction.class
new file mode 100644 (file)
index 0000000..ae331cf
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView$ToolAction.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView.class b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView.class
new file mode 100644 (file)
index 0000000..2c3e22e
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/views/SegmentationView.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$1.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$1.class
new file mode 100644 (file)
index 0000000..0b5d730
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$2.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$2.class
new file mode 100644 (file)
index 0000000..01fdb01
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$2.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$3.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$3.class
new file mode 100644 (file)
index 0000000..f6419a2
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl$3.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl.class
new file mode 100644 (file)
index 0000000..5448699
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/AnnotatedImageControl.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/BrushControl$ScaleChangeListener.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/BrushControl$ScaleChangeListener.class
new file mode 100644 (file)
index 0000000..81476d4
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/BrushControl$ScaleChangeListener.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/BrushControl.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/BrushControl.class
new file mode 100644 (file)
index 0000000..b8dbf7d
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/BrushControl.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/ColorSelector$ControlListener.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/ColorSelector$ControlListener.class
new file mode 100644 (file)
index 0000000..105547c
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/ColorSelector$ControlListener.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/ColorSelector.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/ColorSelector.class
new file mode 100644 (file)
index 0000000..afad48d
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/ColorSelector.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/ImageMenuManager.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/ImageMenuManager.class
new file mode 100644 (file)
index 0000000..aea558d
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/ImageMenuManager.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$1.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$1.class
new file mode 100644 (file)
index 0000000..e6d8d99
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$1.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$2.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$2.class
new file mode 100644 (file)
index 0000000..8ef114d
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$2.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$3.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$3.class
new file mode 100644 (file)
index 0000000..42e939d
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$3.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$4.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$4.class
new file mode 100644 (file)
index 0000000..cc64dd0
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$4.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$State.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$State.class
new file mode 100644 (file)
index 0000000..d4391c9
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer$State.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer.class
new file mode 100644 (file)
index 0000000..0fab82f
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/SwtTimer.class differ
diff --git a/image_annotation/bin/ie/dcu/apps/ist/widgets/Ticker.class b/image_annotation/bin/ie/dcu/apps/ist/widgets/Ticker.class
new file mode 100644 (file)
index 0000000..e95c65e
Binary files /dev/null and b/image_annotation/bin/ie/dcu/apps/ist/widgets/Ticker.class differ
diff --git a/image_annotation/build.xml b/image_annotation/build.xml
new file mode 100644 (file)
index 0000000..e6b752a
--- /dev/null
@@ -0,0 +1,402 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ====================================================================== 
+     Aug 20, 2009 2:11:20 PM                                                        
+
+     istapp
+     The interactive segmentation tool
+                   
+     Kevin McGuinness                                                                
+     ====================================================================== -->
+<project name="istapp" default="default">
+    <description>
+        The interactive segmentation tool
+    </description>
+    
+    <property file="resources/ant/properties" />
+    <property name="src.dir" location="src"/>
+    <property name="build.dir" location="build"/>
+    <property name="lib.dir" location="lib"/>
+    <property name="doc.dir" location="doc"/>
+    <property name="dist.dir" location="dist"/>
+    <property name="bin.jar" value="istapp.jar"/>
+    <property name="src.jar" value="istapp-src.jar"/>
+    <property name="doc.zip" value="istapp-doc.zip"/>
+    <property name="plugins.dir" location="plugins"/>
+    <property name="deb.prefix" value="${build.dir}/packages/debian/usr" />
+
+    <!-- The following four properties are needed by the copy-plugins action -->
+    <property name="bptplugin.dir" location="../BPT Plugin" />
+    <property name="igcplugin.dir" location="../IGC Plugin" />
+    <property name="srgplugin.dir" location="../SRG Plugin" />
+    <property name="sioxplugin.dir" location="../SIOX Plugin" />
+    
+
+    <path id="class.path">
+        <pathelement location="${build.dir}"/>
+        <fileset dir="${lib.dir}" includes="*.jar"/>
+    </path>
+    
+    <!-- Define tasks -->
+    <taskdef name="deb" classpath="resources/ant/lib/ant-deb.jar" 
+        classname="com.googlecode.ant_deb_task.Deb" />
+    <taskdef name="gzip2" classpath="resources/ant/lib/ant-gzip2.jar" 
+        classname="gzip2.GZip2" />
+    <taskdef name="swt_identify" classpath="resources/ant/lib/ant-swt-identify.jar"
+        classname="ie.cdvp.utils.ant.SwtIdentify" />
+    <taskdef name="jsmooth" classpath="resources/ant/lib/jsmoothgen-ant.jar"
+        classname="net.charabia.jsmoothgen.ant.JSmoothGen" />
+    <taskdef name="izpack" classpath="resources/ant/lib/standalone-compiler.jar"
+        classname="com.izforge.izpack.ant.IzPackTask" />
+    
+    <target name="init">
+        <mkdir dir="${build.dir}"/>
+        <mkdir dir="${build.dir}/classes"/>
+        <mkdir dir="${build.dir}/packages"/>
+        <mkdir dir="${build.dir}/temp"/>
+        <mkdir dir="${doc.dir}"/>
+        <mkdir dir="${dist.dir}"/>
+    </target>
+    
+    <target name="clean">
+        <delete dir="${build.dir}/classes" />
+        <delete dir="${build.dir}/packages" />
+        <delete dir="${build.dir}/temp" />
+        <delete dir="${doc.dir}" />
+        <delete dir="${dist.dir}" />
+    </target>
+    
+    <target name="compile" depends="init">
+        <javac srcdir="${src.dir}" 
+            destdir="${build.dir}/classes" 
+            debug="${java.debug}"
+            source="${java.source.version}"
+            target="${java.target.version}">
+            <classpath refid="class.path"/>
+        </javac>
+        <!-- copy resources -->
+        <copy todir="${build.dir}/classes">
+            <fileset dir="${src.dir}">
+                <include name="**/*.html" />
+            </fileset>
+        </copy>
+    </target>
+    
+    <target name="doc" depends="init">
+        <javadoc sourcepath="${src.dir}" 
+            destdir="${doc.dir}/api" 
+            author="true" 
+            version="true" 
+            use="true" 
+            windowtitle="${app.name}" 
+            classpathref="class.path">
+        <link href="http://java.sun.com/javase/6/docs/api/"/>
+        </javadoc>
+    </target>
+    
+    <target name="dist" depends="compile,doc">
+        <!-- class file jar -->
+        <jar destfile="${dist.dir}/${bin.jar}">
+            <fileset dir="${build.dir}/classes">
+                <include name="**/*"/>
+            </fileset>
+        </jar>
+        <!-- source code jar -->
+        <jar destfile="${dist.dir}/${src.jar}">
+            <fileset dir="${src.dir}">
+                <include name="**/*.java"/>
+            </fileset>
+        </jar>
+        <!-- documentation zip -->
+        <zip destfile="${dist.dir}/${doc.zip}">
+            <fileset dir="${doc.dir}">
+                <include name="**/*"/>
+            </fileset>
+        </zip>
+    </target>
+    
+    <target name="copy-plugins">
+        <!-- Copy plugins from the other projects -->
+        <copy todir="${plugins.dir}">
+            <fileset dir="${bptplugin.dir}/dist/"  includes="BPTPlugin.plugin/**/*" />
+            <fileset dir="${igcplugin.dir}/dist/"  includes="IGCPlugin.plugin/**/*" />
+            <fileset dir="${srgplugin.dir}/dist/"  includes="SRGPlugin.plugin/**/*" />
+            <fileset dir="${sioxplugin.dir}/dist/" includes="SIOXPlugin.plugin/**/*" />
+        </copy>
+    </target>
+    
+    <target name="package-mac" depends="dist">
+        <!-- Make the folders -->
+        <mkdir dir="${dist.dir}/${app.name}.app"/>
+        <mkdir dir="${dist.dir}/${app.name}.app/Contents"/>
+        <mkdir dir="${dist.dir}/${app.name}.app/Contents/MacOS"/>
+        <mkdir dir="${dist.dir}/${app.name}.app/Contents/Resources"/>
+        <mkdir dir="${dist.dir}/${app.name}.app/Contents/Resources/Java"/>
+        <mkdir dir="${dist.dir}/${app.name}.app/Contents/Resources/Java/plugins"/>
+        
+        <!-- Copy and filter plist and PkgInfo -->
+        <copy todir="${dist.dir}/${app.name}.app/Contents/" overwrite="true">
+            <fileset dir="resources/plaf/mac/" includes="Info.plist,PkgInfo"/>
+            <filterset>
+                <filter token="name" value="${app.name}"/>
+                <filter token="version" value="${app.version}"/>
+                <filter token="synopsis" value="${app.synopsis}"/>
+                <filter token="icons" value="icon.icns"/>
+                <filter token="exename" value="ist"/>
+            </filterset>
+        </copy>
+        
+        <!-- Copy and filter launch script -->
+        <copy todir="${dist.dir}/${app.name}.app/Contents/MacOS" overwrite="true">
+            <fileset dir="resources/plaf/mac/" includes="ist" />
+            <filterset>
+                <filter token="appmain" value="${app.main}"/>
+            </filterset>
+        </copy>
+        
+        <!-- Copy resources -->
+        <copy todir="${dist.dir}/${app.name}.app/Contents/Resources">
+            <fileset dir="resources/plaf/mac" includes="icon.icns" />
+            <fileset dir="." includes="resources/config/*" />
+            <fileset dir="." includes="resources/icons/*" />
+            <fileset dir="." includes="resources/doc/*" />
+        </copy>
+        
+        <!-- Copy jars -->
+        <copy todir="${dist.dir}/${app.name}.app/Contents/Resources/Java">
+            <fileset dir="dist" includes="${bin.jar}" />
+            <fileset dir="lib" includes="istapi.jar,swt-cocoa-32.jar,swt-cocoa-64.jar,jface.jar" />
+        </copy>
+        
+        <!-- Copy plugins -->
+        <copy todir="${dist.dir}/${app.name}.app/Contents/Resources/Java/plugins">
+            <fileset dir="${plugins.dir}" >
+                <include name="**/*" />
+                <exclude name="**/*.dll" />
+                <exclude name="**/*.so" />
+            </fileset>
+        </copy>
+    
+        <!-- Make executable -->
+        <chmod perm="0755" file="${dist.dir}/${app.name}.app/Contents/MacOS/ist" />
+        
+        <!-- Bundle into a zip file -->
+        <zip destfile="${dist.dir}/${app.package}_${app.version}_mac.zip">
+            <zipfileset dir="${dist.dir}/${app.name}.app" prefix="${app.name}.app">
+                <include name="**/*" />
+                <exclude name="Contents/MacOS/*"/>
+            </zipfileset>
+        
+            <zipfileset dir="${dist.dir}/${app.name}.app" prefix="${app.name}.app" filemode="755">
+                <include name="Contents/MacOS/*" />
+            </zipfileset>
+        </zip>
+    </target>
+    
+    <target name="package-debian" depends="dist">
+        <!-- Create folder structure -->
+        <mkdir dir="${build.dir}/packages/debian/usr/bin" />
+        <mkdir dir="${build.dir}/packages/debian/usr/share/${app.package}" />
+        <mkdir dir="${build.dir}/packages/debian/usr/share/doc/${app.package}" />
+        <mkdir dir="${build.dir}/packages/debian/usr/share/applications" />
+        <mkdir dir="${build.dir}/packages/debian/usr/share/man/man1" />
+        <mkdir dir="${build.dir}/packages/debian/usr/share/icons/hicolor" />
+        
+        <!-- Man page & copyright-->
+          <gzip2 destfile="${build.dir}/packages/debian/usr/share/man/man1/ist.1.gz"
+            src="resources/plaf/debian/ist.1" level="9" filesystem="unix" />
+        <copy todir="${build.dir}/packages/debian/usr/share/doc/${app.package}"
+            file="resources/plaf/debian/copyright" />
+            
+        <!-- Shortcuts & icons -->
+        <copy tofile="${build.dir}/packages/debian/usr/share/applications/${app.package}.desktop"
+            file="resources/plaf/debian/desktop" />
+        <copy todir="${build.dir}/packages/debian/usr/share/icons/hicolor">
+            <fileset dir="resources/icons" includes="icon-*.png" />
+            <regexpmapper from="icon-(.*)\.png" to="\1x\1/apps/${app.package}.png" />
+        </copy>
+            
+        <!-- Binary (launcher) -->
+        <copy tofile="${build.dir}/packages/debian/usr/bin/ist" 
+            file="resources/plaf/debian/ist" overwrite="true">
+            <filterset>
+                <filter token="jars" value="${bin.jar}:istapi.jar:jface.jar:swt.jar"/>
+                <filter token="data" value="/usr/share/${app.package}" />
+                <filter token="main" value="${app.main}" />
+            </filterset>
+        </copy> 
+        
+        <!-- Application data -->
+        <copy todir="${build.dir}/packages/debian/usr/share/${app.package}">
+            <fileset dir="dist" includes="${bin.jar}"/>
+            <fileset dir="lib" includes="istapi.jar,jface.jar" />
+            <fileset dir="." includes="resources/config/**/*" />
+            <fileset dir="." includes="resources/icons/**/*" />
+            <fileset dir="." includes="resources/doc/**/*" />
+            <fileset dir="." >
+                <include name="plugins/**/*" />
+                <exclude name="plugins/**/*.jnilib" />
+                <exclude name="plugins/**/*.dll" />
+            </fileset>
+        </copy>
+         
+        <!-- Build i386 deb -->
+        <deb todir="dist" package="${app.package}" priority="extra"
+            section="graphics" architecture="i386"
+            depends="sun-java5-jre | sun-java6-jre"
+            postinst="resources/plaf/debian/postinst"
+            postrm="resources/plaf/debian/postrm" >
+            
+            <version upstream="${app.version}" debian="1" />
+            <changelog file="resources/plaf/debian/changelog" />
+            <changelog file="resources/plaf/debian/changelog" debian="true" />
+            <maintainer name="${app.author}" email="${app.email}" />
+            
+            <description synopsis="${app.synopsis}">
+             A tool that allows you to interactively extract an object
+             from an image using a variety of scribble based algorithms
+            </description>
+            
+            <tarfileset dir="${build.dir}/packages/debian/" includes="**/*" excludes="usr/bin/*" />
+            <tarfileset dir="${build.dir}/packages/debian/" includes="usr/bin/*" filemode="0755" />
+            <tarfileset file="${lib.dir}/swt-gtk.jar" fullpath="usr/share/${app.package}/swt.jar"/>
+         </deb>
+         
+         <!-- Build amd64 deb -->
+         <deb todir="dist" package="${app.package}" priority="extra"
+             section="graphics" architecture="amd64"
+             depends="sun-java5-jre | sun-java6-jre"
+             postinst="resources/plaf/debian/postinst"
+             postrm="resources/plaf/debian/postrm" >
+
+             <version upstream="${app.version}" debian="1" />
+             <changelog file="resources/plaf/debian/changelog" />
+             <changelog file="resources/plaf/debian/changelog" debian="true" />
+             <maintainer name="${app.author}" email="${app.email}" />
+
+             <description synopsis="${app.synopsis}">
+             A tool that allows you to interactively extract an object
+             from an image using a variety of scribble based algorithms
+             </description>
+
+             <tarfileset dir="${build.dir}/packages/debian/" includes="**/*" excludes="usr/bin/*" />
+             <tarfileset dir="${build.dir}/packages/debian/" includes="usr/bin/*" filemode="0755" />
+             <tarfileset file="${lib.dir}/swt-gtk-64.jar" fullpath="usr/share/${app.package}/swt.jar"/>
+          </deb>
+    </target>
+    
+    <target name="package-linux" depends="dist">
+        <mkdir dir="${build.dir}/packages/linux" />
+        
+        <!-- common stuff -->
+        <copy todir="${build.dir}/packages/linux" >
+            <fileset dir="dist" includes="istapp.jar"/>
+            <fileset dir="lib" includes="istapi.jar"/>
+            <fileset dir="lib" includes="jface.jar"/>
+            <fileset dir="." includes="resources/config/**/*"/>
+            <fileset dir="." includes="resources/icons/**/*"/>
+            <fileset dir="." includes="resources/doc/**/*"/>
+        </copy>
+        
+        <!-- plugins -->
+        <copy todir="${build.dir}/packages/linux" >
+            <fileset dir="." >
+                <include name="plugins/**/*" />
+                <exclude name="plugins/**/*.dll" />
+                <exclude name="plugins/**/*.jnilib" />
+                <exclude name="plugins/**/*.dynlib" />
+            </fileset>
+        </copy>
+        
+        <!-- tar i386 -->
+        <tar destfile="${dist.dir}/${app.package}_${app.version}_linux_i386.tar.gz"
+            compression="gzip">
+            <tarfileset dir="${build.dir}/packages/linux"
+                includes="**/*"
+                prefix="${app.package}_${app.version}"/>
+            <tarfileset dir="${lib.dir}"
+                includes="swt-gtk.jar"
+                fullpath="${app.package}_${app.version}/swt.jar" />
+            <tarfileset file="resources/plaf/linux/ist" 
+                fullpath="${app.package}_${app.version}/ist"
+                filemode="0755"/>
+        </tar>
+        
+        <!-- tar x86_64 -->
+        <tar destfile="${dist.dir}/${app.package}_${app.version}_linux_x86_64.tar.gz"
+            compression="gzip">
+            <tarfileset dir="${build.dir}/packages/linux"
+                includes="**/*"
+                prefix="${app.package}_${app.version}"/>
+            <tarfileset dir="${lib.dir}"
+                includes="swt-gtk-64.jar"
+                fullpath="${app.package}_${app.version}/swt.jar" />
+            <tarfileset file="resources/plaf/linux/ist" 
+                fullpath="${app.package}_${app.version}/ist"
+                filemode="0755"/>
+        </tar>
+    </target>
+    
+    <target name="package-windows" depends="dist">
+     
+        <!-- Make windows package -->
+        <mkdir dir="${build.dir}/packages/windows" />
+        <jsmooth project="resources/plaf/windows/ist.jsmooth"
+            skeletonroot="resources/plaf/windows/skeletons" />
+        <move file="resources/plaf/windows/ist.exe" 
+            todir="${build.dir}/packages/windows" />
+        <copy todir="${build.dir}/packages/windows" >
+            <fileset dir="dist" includes="istapp.jar"/>
+            <fileset dir="lib" includes="istapi.jar"/>
+            <fileset dir="lib" includes="jface.jar"/>
+            <fileset dir="lib" includes="swt-win.jar"/>
+            <fileset dir="." includes="resources/config/**/*"/>
+            <fileset dir="." includes="resources/icons/**/*"/>
+            <fileset dir="." includes="resources/doc/**/*"/>
+        </copy>
+        <copy todir="${build.dir}/packages/windows" >
+            <fileset dir="." >
+                <include name="plugins/**/*" />
+                <exclude name="plugins/**/*.so" />
+                <exclude name="plugins/**/*.jnilib" />
+                <exclude name="plugins/**/*.dynlib" />
+            </fileset>
+        </copy>
+        
+        <!-- Build an installer -->
+        <copy todir="build/temp" 
+            file="resources/plaf/windows/install.xml" overwrite="true">
+            <filterset>
+                <filter token="name" value="${app.name}" />
+                <filter token="version" value="${app.version}" />
+                <filter token="author" value="${app.author}" />
+                <filter token="email" value="${app.email}" />
+                <filter token="website" value="${app.website}" />
+            </filterset>
+        </copy>
+        <izpack input="build/temp/install.xml"
+            output="dist/${app.package}_${app.version}_win32.jar"
+            installerType="standard" basedir="." />
+        <copy todir="build/temp" 
+            file="resources/plaf/windows/installer.jsmooth" overwrite="true">
+            <filterset>
+                <filter token="input" 
+                    value="../../dist/${app.package}_${app.version}_win32.jar" />
+                <filter token="output" 
+                    value="../../dist/${app.package}_${app.version}_win32.exe" />
+                <filter token="icon" 
+                    value="../../resources/plaf/windows/installer.ico" />
+            </filterset>
+        </copy>
+        <jsmooth project="build/temp/installer.jsmooth"
+            skeletonroot="resources/plaf/windows/skeletons" />
+    </target>
+    
+    
+    
+    <target name="package" depends="package-mac,package-linux,package-debian,package-windows">
+    </target>
+    
+    <target name="default" depends="clean,package">
+    </target>
+
+</project>
diff --git a/image_annotation/lib/._swt-cocoa-32.jar b/image_annotation/lib/._swt-cocoa-32.jar
new file mode 100644 (file)
index 0000000..aca5ab2
Binary files /dev/null and b/image_annotation/lib/._swt-cocoa-32.jar differ
diff --git a/image_annotation/lib/._swt-cocoa-64.jar b/image_annotation/lib/._swt-cocoa-64.jar
new file mode 100644 (file)
index 0000000..90875d7
Binary files /dev/null and b/image_annotation/lib/._swt-cocoa-64.jar differ
diff --git a/image_annotation/lib/.classpath b/image_annotation/lib/.classpath
new file mode 100644 (file)
index 0000000..4027147
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="lib" path="._swt-cocoa-32.jar"/>
+       <classpathentry kind="lib" path="._swt-cocoa-64.jar"/>
+       <classpathentry kind="lib" path="istapi-src.jar"/>
+       <classpathentry kind="lib" path="istapi.jar"/>
+       <classpathentry kind="lib" path="jface.jar"/>
+       <classpathentry kind="lib" path="swt-cocoa-32.jar"/>
+       <classpathentry kind="lib" path="swt-cocoa-64.jar"/>
+       <classpathentry kind="lib" path="swt-gtk-64.jar"/>
+       <classpathentry kind="lib" path="swt-gtk.jar"/>
+       <classpathentry kind="lib" path="swt-win.jar"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/image_annotation/lib/.project b/image_annotation/lib/.project
new file mode 100644 (file)
index 0000000..9f09891
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>TestAnn</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/image_annotation/lib/istapi-doc.zip b/image_annotation/lib/istapi-doc.zip
new file mode 100644 (file)
index 0000000..90a6377
Binary files /dev/null and b/image_annotation/lib/istapi-doc.zip differ
diff --git a/image_annotation/lib/istapi-src.jar b/image_annotation/lib/istapi-src.jar
new file mode 100644 (file)
index 0000000..63dd31d
Binary files /dev/null and b/image_annotation/lib/istapi-src.jar differ
diff --git a/image_annotation/lib/istapi.jar b/image_annotation/lib/istapi.jar
new file mode 100644 (file)
index 0000000..4ad357a
Binary files /dev/null and b/image_annotation/lib/istapi.jar differ
diff --git a/image_annotation/lib/jface.jar b/image_annotation/lib/jface.jar
new file mode 100644 (file)
index 0000000..f515a8f
Binary files /dev/null and b/image_annotation/lib/jface.jar differ
diff --git a/image_annotation/lib/swt-cocoa-32.jar b/image_annotation/lib/swt-cocoa-32.jar
new file mode 100644 (file)
index 0000000..d42da95
Binary files /dev/null and b/image_annotation/lib/swt-cocoa-32.jar differ
diff --git a/image_annotation/lib/swt-cocoa-64.jar b/image_annotation/lib/swt-cocoa-64.jar
new file mode 100644 (file)
index 0000000..228da89
Binary files /dev/null and b/image_annotation/lib/swt-cocoa-64.jar differ
diff --git a/image_annotation/lib/swt-gtk-64.jar b/image_annotation/lib/swt-gtk-64.jar
new file mode 100644 (file)
index 0000000..4ce079f
Binary files /dev/null and b/image_annotation/lib/swt-gtk-64.jar differ
diff --git a/image_annotation/lib/swt-gtk.jar b/image_annotation/lib/swt-gtk.jar
new file mode 100644 (file)
index 0000000..5c94f6e
Binary files /dev/null and b/image_annotation/lib/swt-gtk.jar differ
diff --git a/image_annotation/lib/swt-win.jar b/image_annotation/lib/swt-win.jar
new file mode 100644 (file)
index 0000000..5eb6d90
Binary files /dev/null and b/image_annotation/lib/swt-win.jar differ
diff --git a/image_annotation/plugins/BPTPlugin.plugin/bptplugin.jar b/image_annotation/plugins/BPTPlugin.plugin/bptplugin.jar
new file mode 100644 (file)
index 0000000..d4025cf
Binary files /dev/null and b/image_annotation/plugins/BPTPlugin.plugin/bptplugin.jar differ
diff --git a/image_annotation/plugins/BPTPlugin.plugin/jbpt.dll b/image_annotation/plugins/BPTPlugin.plugin/jbpt.dll
new file mode 100644 (file)
index 0000000..d12f777
Binary files /dev/null and b/image_annotation/plugins/BPTPlugin.plugin/jbpt.dll differ
diff --git a/image_annotation/plugins/BPTPlugin.plugin/libjbpt.jnilib b/image_annotation/plugins/BPTPlugin.plugin/libjbpt.jnilib
new file mode 100644 (file)
index 0000000..77039d7
Binary files /dev/null and b/image_annotation/plugins/BPTPlugin.plugin/libjbpt.jnilib differ
diff --git a/image_annotation/plugins/BPTPlugin.plugin/plugin.xml b/image_annotation/plugins/BPTPlugin.plugin/plugin.xml
new file mode 100644 (file)
index 0000000..4ae529d
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<plugin>
+       <meta name="name" value="BPT Plugin" />
+       <meta name="description" value="Binary Partition Tree Plugin" />
+       <meta name="vendor" value="Dublin City University" />
+       <meta name="author" value="Kevin McGuinness" />
+       <meta name="email" value="kevin.mcguinness@gmail.com" />
+       <meta name="segmenter" value="ie.dcu.segment.algorithm.BptSegmenter" /> 
+       <jar file="bptplugin.jar" />
+</plugin>
diff --git a/image_annotation/plugins/IGCPlugin.plugin/igcplugin.jar b/image_annotation/plugins/IGCPlugin.plugin/igcplugin.jar
new file mode 100644 (file)
index 0000000..c85393b
Binary files /dev/null and b/image_annotation/plugins/IGCPlugin.plugin/igcplugin.jar differ
diff --git a/image_annotation/plugins/IGCPlugin.plugin/jigc.dll b/image_annotation/plugins/IGCPlugin.plugin/jigc.dll
new file mode 100644 (file)
index 0000000..b4ee98c
Binary files /dev/null and b/image_annotation/plugins/IGCPlugin.plugin/jigc.dll differ
diff --git a/image_annotation/plugins/IGCPlugin.plugin/libjigc.jnilib b/image_annotation/plugins/IGCPlugin.plugin/libjigc.jnilib
new file mode 100644 (file)
index 0000000..6ff9817
Binary files /dev/null and b/image_annotation/plugins/IGCPlugin.plugin/libjigc.jnilib differ
diff --git a/image_annotation/plugins/IGCPlugin.plugin/plugin.xml b/image_annotation/plugins/IGCPlugin.plugin/plugin.xml
new file mode 100644 (file)
index 0000000..2b7ae2e
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<plugin>
+       <meta name="name" value="IGC Plugin" />
+       <meta name="description" value="Interactive Graph Cuts Plugin" />
+       <meta name="vendor" value="Dublin City University" />
+       <meta name="author" value="Kevin McGuinness" />
+       <meta name="email" value="kevin.mcguinness@gmail.com" />
+       <meta name="segmenter" value="ie.dcu.segment.algorithm.IgcSegmenter" /> 
+       <jar file="igcplugin.jar" />
+</plugin>
diff --git a/image_annotation/plugins/SIOXPlugin.plugin/plugin.xml b/image_annotation/plugins/SIOXPlugin.plugin/plugin.xml
new file mode 100644 (file)
index 0000000..623ad7b
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<plugin>
+       <meta name="name" value="SIOX Plugin" />
+       <meta name="description" value="Simple Interactive Object Extraction Plugin" />
+       <meta name="vendor" value="Dublin City University" />
+       <meta name="author" value="Kevin McGuinness" />
+       <meta name="email" value="kevin.mcguinness@gmail.com" />
+       <meta name="segmenter" value="ie.dcu.segment.algorithm.SioxSegmenter" />        
+       <jar file="sioxplugin.jar" />
+       <jar file="sioxapi.jar" />
+</plugin>
diff --git a/image_annotation/plugins/SIOXPlugin.plugin/sioxapi.jar b/image_annotation/plugins/SIOXPlugin.plugin/sioxapi.jar
new file mode 100644 (file)
index 0000000..4c121b2
Binary files /dev/null and b/image_annotation/plugins/SIOXPlugin.plugin/sioxapi.jar differ
diff --git a/image_annotation/plugins/SIOXPlugin.plugin/sioxplugin.jar b/image_annotation/plugins/SIOXPlugin.plugin/sioxplugin.jar
new file mode 100644 (file)
index 0000000..31f959a
Binary files /dev/null and b/image_annotation/plugins/SIOXPlugin.plugin/sioxplugin.jar differ
diff --git a/image_annotation/plugins/SRGPlugin.plugin/jsrg.dll b/image_annotation/plugins/SRGPlugin.plugin/jsrg.dll
new file mode 100644 (file)
index 0000000..c381fae
Binary files /dev/null and b/image_annotation/plugins/SRGPlugin.plugin/jsrg.dll differ
diff --git a/image_annotation/plugins/SRGPlugin.plugin/libjsrg.jnilib b/image_annotation/plugins/SRGPlugin.plugin/libjsrg.jnilib
new file mode 100644 (file)
index 0000000..46427e8
Binary files /dev/null and b/image_annotation/plugins/SRGPlugin.plugin/libjsrg.jnilib differ
diff --git a/image_annotation/plugins/SRGPlugin.plugin/plugin.xml b/image_annotation/plugins/SRGPlugin.plugin/plugin.xml
new file mode 100644 (file)
index 0000000..4061f98
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<plugin>
+       <meta name="name" value="SRG Plugin" />
+       <meta name="description" value="Seeded Region Growing Plugin" />
+       <meta name="vendor" value="Dublin City University" />
+       <meta name="author" value="Kevin McGuinness" />
+       <meta name="email" value="kevin.mcguinness@gmail.com" />
+       <meta name="segmenter" value="ie.dcu.segment.algorithm.SrgSegmenter" /> 
+       <jar file="srgplugin.jar" />
+</plugin>
diff --git a/image_annotation/plugins/SRGPlugin.plugin/srgplugin.jar b/image_annotation/plugins/SRGPlugin.plugin/srgplugin.jar
new file mode 100644 (file)
index 0000000..c888c62
Binary files /dev/null and b/image_annotation/plugins/SRGPlugin.plugin/srgplugin.jar differ
diff --git a/image_annotation/resources/ant/lib/ant-deb.jar b/image_annotation/resources/ant/lib/ant-deb.jar
new file mode 100644 (file)
index 0000000..f602bec
Binary files /dev/null and b/image_annotation/resources/ant/lib/ant-deb.jar differ
diff --git a/image_annotation/resources/ant/lib/ant-gzip2.jar b/image_annotation/resources/ant/lib/ant-gzip2.jar
new file mode 100644 (file)
index 0000000..271f123
Binary files /dev/null and b/image_annotation/resources/ant/lib/ant-gzip2.jar differ
diff --git a/image_annotation/resources/ant/lib/ant-passwd-task.jar b/image_annotation/resources/ant/lib/ant-passwd-task.jar
new file mode 100644 (file)
index 0000000..b4f4b76
Binary files /dev/null and b/image_annotation/resources/ant/lib/ant-passwd-task.jar differ
diff --git a/image_annotation/resources/ant/lib/ant-swt-identify.jar b/image_annotation/resources/ant/lib/ant-swt-identify.jar
new file mode 100644 (file)
index 0000000..daddc1c
Binary files /dev/null and b/image_annotation/resources/ant/lib/ant-swt-identify.jar differ
diff --git a/image_annotation/resources/ant/lib/jsmoothgen-ant.jar b/image_annotation/resources/ant/lib/jsmoothgen-ant.jar
new file mode 100644 (file)
index 0000000..c9e283d
Binary files /dev/null and b/image_annotation/resources/ant/lib/jsmoothgen-ant.jar differ
diff --git a/image_annotation/resources/ant/lib/standalone-compiler.jar b/image_annotation/resources/ant/lib/standalone-compiler.jar
new file mode 100644 (file)
index 0000000..2762975
Binary files /dev/null and b/image_annotation/resources/ant/lib/standalone-compiler.jar differ
diff --git a/image_annotation/resources/ant/properties b/image_annotation/resources/ant/properties
new file mode 100644 (file)
index 0000000..38b429c
--- /dev/null
@@ -0,0 +1,14 @@
+app.name=Interactive Segmentation Tool
+app.package=ist
+app.version=1.3.4
+app.author=Kevin McGuinness
+app.email=kevin.mcguinness@eeng.dcu.ie
+app.website=http://kspace.cdvp.dcu.ie/public/interactive-segmentation
+app.synopsis=The CDVP Interactive Segmentation Tool
+app.main=ie.dcu.apps.ist.Main
+
+# Compilation properties
+java.debug=off
+java.source.version=1.5
+java.target.version=1.5
+
diff --git a/image_annotation/resources/config/actions.mac.properties b/image_annotation/resources/config/actions.mac.properties
new file mode 100644 (file)
index 0000000..8a282fa
--- /dev/null
@@ -0,0 +1,108 @@
+
+OpenAction.dialog.text=Open an image or saved context
+OpenAction.dialog.filter.exts=*.jpg;*.jpeg;*.png;*.gif;*.bmp;*.ctx
+OpenAction.dialog.filter.text=Image and Context Files
+
+SaveAction.dialog.text=Save Segmentation Context
+SaveAction.dialog.filter.exts=*.ctx
+SaveAction.dialog.filter.text=Segmentation Context Files
+
+ExportViewAction.dialog.text=Export View As Image
+ExportViewAction.dialog.filter.exts=*.jpg;*.jpeg;*.png;*.gif;*.bmp;
+ExportViewAction.dialog.filter.text=Image Files
+
+OpenExperimentAction.dialog.text=Open an experiment file
+OpenExperimentAction.dialog.filter.exts=*.exp
+OpenExperimentAction.dialog.filter.text=Experiment Files
+
+# Actions
+action.OpenAction.text=&Open...@Command+O
+action.OpenAction.image=file:resources/icons/open.png
+action.OpenAction.tooltip=Open image
+
+action.SaveAction.text=&Save@Command+S
+action.SaveAction.image=file:resources/icons/save.png
+action.SaveAction.tooltip=Save segmentation context
+
+action.SaveAsAction.text=S&ave As...@Command+Shift+S
+action.SaveAsAction.image=file:resources/icons/save-as.png
+action.SaveAsAction.tooltip=Save segmentation context as...
+
+action.ExportViewAction.text=&Current View...@Command+Alt+V
+action.ExportViewAction.image=file:resources/icons/image.png
+action.ExportViewAction.tooltip=Export view as image
+
+action.ExportImageMapAction.text=&HTML Image Map...@Command+Alt+H
+action.ExportImageMapAction.image=file:resources/icons/html.png
+action.ExportImageMapAction.tooltip=Export objects as HTML image map
+
+action.ExportTransparentPNGAction.text=Export Transparent &PNG...@Command+Alt+P
+action.ExportTransparentPNGAction.image=file:resources/icons/image.png
+action.ExportTransparentPNGAction.tooltip=Export a PNG of the current segmentation with a transparent background
+
+action.ImportAction.text=&Import...
+action.ImportAction.image=file:resources/icons/import.png
+action.ImportAction.tooltip=Import images
+
+action.PrintAction.text=&Print@Command+P
+action.PrintAction.image=file:resources/icons/print.png
+action.PrintAction.tooltip=Print view
+
+action.ExitAction.text=E&xit@Command+Q
+action.ExitAction.image=file:resources/icons/exit.png
+action.ExitAction.tooltip=Quit the application
+
+action.UndoAction.text=&Undo@Command+Z
+action.UndoAction.image=file:resources/icons/undo.png
+action.UndoAction.tooltip=Undo last markup
+
+action.RedoAction.text=&Redo@Command+Y
+action.RedoAction.image=file:resources/icons/redo.png
+action.RedoAction.tooltip=Redo markup
+
+action.CopyAction.text=&Copy@Command+C
+action.CopyAction.image=file:resources/icons/copy.png
+action.CopyAction.tooltip=Copy view to clipboard as image
+
+action.PreferencesAction.text=&Preferences...@Command+,
+action.PreferencesAction.image=file:resources/icons/preferences.png
+action.PreferencesAction.tooltip=Change application settings
+
+action.AddFilesAction.text=&Add Files...@Command+A
+action.AddFilesAction.image=file:resources/icons/add.png
+action.AddFilesAction.tooltip=Add image files to project
+
+action.RemoveFilesAction.text=&Remove Files@Command+R
+action.RemoveFilesAction.image=file:resources/icons/remove.png
+action.RemoveFilesAction.tooltip=Remove selected image files from project
+
+action.PreviousAction.text=&Previous@Command+[
+action.PreviousAction.image=file:resources/icons/previous.png
+action.PreviousAction.tooltip=Move to previous image in directory
+
+action.NextAction.text=&Next@Command+]
+action.NextAction.image=file:resources/icons/next.png
+action.NextAction.tooltip=Move to next image in directory
+
+action.HelpAction.text=&Help Contents...@Command+F1
+action.HelpAction.image=file:resources/icons/help.png
+action.HelpAction.tooltip=Show application help browser
+action.HelpAction.helpURL=http://kspace.cdvp.dcu.ie/public/interactive-segmentation/doc/help.html
+
+action.AboutAction.text=&About...
+action.AboutAction.image=file:resources/icons/about.png
+action.AboutAction.tooltip=About the application
+action.AboutAction.aboutImage=file:resources/icons/about-box.png
+
+action.OpenExperimentAction.text=Open &Experiment...
+action.OpenExperimentAction.image=file:resources/icons/experiment.png
+action.OpenExperimentAction.tooltip=Open an experiment file and switch to experiment mode
+
+action.ConfigureSegmenterAction.text=&Configure Segmenter...@Command+Shift+C
+action.ConfigureSegmenterAction.image=file:resources/icons/preferences.png
+action.ConfigureSegmenterAction.tooltip=Configure segmenter parameters
+
+action.SelectSegmenterAction.NA=Algorithm not available on this platform
+
+
+
diff --git a/image_annotation/resources/config/actions.properties b/image_annotation/resources/config/actions.properties
new file mode 100644 (file)
index 0000000..f2ddcb0
--- /dev/null
@@ -0,0 +1,106 @@
+
+OpenAction.dialog.text=Open an image or saved context
+OpenAction.dialog.filter.exts=*.jpg;*.jpeg;*.png;*.gif;*.bmp;*.ctx
+OpenAction.dialog.filter.text=Image and Context Files
+
+SaveAction.dialog.text=Save Segmentation Context
+SaveAction.dialog.filter.exts=*.ctx
+SaveAction.dialog.filter.text=Segmentation Context Files
+
+ExportViewAction.dialog.text=Export View As Image
+ExportViewAction.dialog.filter.exts=*.jpg;*.jpeg;*.png;*.gif;*.bmp;
+ExportViewAction.dialog.filter.text=Image Files
+
+OpenExperimentAction.dialog.text=Open an experiment file
+OpenExperimentAction.dialog.filter.exts=*.exp
+OpenExperimentAction.dialog.filter.text=Experiment Files
+
+# Actions
+action.OpenAction.text=&Open...@Ctrl+O
+action.OpenAction.image=file:resources/icons/open.png
+action.OpenAction.tooltip=Open image
+
+action.SaveAction.text=&Save@Ctrl+S
+action.SaveAction.image=file:resources/icons/save.png
+action.SaveAction.tooltip=Save segmentation context
+
+action.SaveAsAction.text=S&ave As...@Ctrl+Shift+S
+action.SaveAsAction.image=file:resources/icons/save-as.png
+action.SaveAsAction.tooltip=Save segmentation context as...
+
+action.ExportViewAction.text=&Current View...@Ctrl+Shift+V
+action.ExportViewAction.image=file:resources/icons/image.png
+action.ExportViewAction.tooltip=Export view as image
+
+action.ExportImageMapAction.text=&HTML Image Map...@Ctrl+Shift+H
+action.ExportImageMapAction.image=file:resources/icons/html.png
+action.ExportImageMapAction.tooltip=Export objects as HTML image map
+
+action.ExportTransparentPNGAction.text=Export Transparent &PNG...@Ctrl+Shift+P
+action.ExportTransparentPNGAction.image=file:resources/icons/image.png
+action.ExportTransparentPNGAction.tooltip=Export a PNG of the current segmentation with a transparent background
+
+
+action.ImportAction.text=&Import...
+action.ImportAction.image=file:resources/icons/import.png
+action.ImportAction.tooltip=Import images
+
+action.PrintAction.text=&Print@Ctrl+P
+action.PrintAction.image=file:resources/icons/print.png
+action.PrintAction.tooltip=Print view
+
+action.ExitAction.text=E&xit@Ctrl+Q
+action.ExitAction.image=file:resources/icons/exit.png
+action.ExitAction.tooltip=Quit the application
+
+action.UndoAction.text=&Undo@Ctrl+Z
+action.UndoAction.image=file:resources/icons/undo.png
+action.UndoAction.tooltip=Undo last markup
+
+action.RedoAction.text=&Redo@Ctrl+Y
+action.RedoAction.image=file:resources/icons/redo.png
+action.RedoAction.tooltip=Redo markup
+
+action.CopyAction.text=&Copy@Ctrl+C
+action.CopyAction.image=file:resources/icons/copy.png
+action.CopyAction.tooltip=Copy view to clipboard as image
+
+action.PreferencesAction.text=&Preferences...
+action.PreferencesAction.image=file:resources/icons/preferences.png
+action.PreferencesAction.tooltip=Change application settings
+
+action.AddFilesAction.text=&Add Files...@Ctrl+A
+action.AddFilesAction.image=file:resources/icons/add.png
+action.AddFilesAction.tooltip=Add image files to project
+
+action.RemoveFilesAction.text=&Remove Files@Ctrl+R
+action.RemoveFilesAction.image=file:resources/icons/remove.png
+action.RemoveFilesAction.tooltip=Remove selected image files from project
+
+action.PreviousAction.text=&Previous@Ctrl+[
+action.PreviousAction.image=file:resources/icons/previous.png
+action.PreviousAction.tooltip=Move to previous image in directory
+
+action.NextAction.text=&Next@Ctrl+]
+action.NextAction.image=file:resources/icons/next.png
+action.NextAction.tooltip=Move to next image in directory
+
+action.HelpAction.text=&Help Contents...@Ctrl+F1
+action.HelpAction.image=file:resources/icons/help.png
+action.HelpAction.tooltip=Show application help browser
+action.HelpAction.helpURL=http://kspace.cdvp.dcu.ie/public/interactive-segmentation/doc/help.html
+
+action.AboutAction.text=&About...
+action.AboutAction.image=file:resources/icons/about.png
+action.AboutAction.tooltip=About the application
+action.AboutAction.aboutImage=file:resources/icons/about-box.png
+
+action.OpenExperimentAction.text=Open &Experiment...
+action.OpenExperimentAction.image=file:resources/icons/experiment.png
+action.OpenExperimentAction.tooltip=Open an experiment file and switch to experiment mode
+
+action.ConfigureSegmenterAction.text=&Configure Segmenter...@Ctrl+Shift+C
+action.ConfigureSegmenterAction.image=file:resources/icons/preferences.png
+action.ConfigureSegmenterAction.tooltip=Configure segmenter parameters
+
+action.SelectSegmenterAction.NA=Algorithm not available on this platform
diff --git a/image_annotation/resources/config/application.mac.properties b/image_annotation/resources/config/application.mac.properties
new file mode 100644 (file)
index 0000000..096ea68
--- /dev/null
@@ -0,0 +1,25 @@
+
+AppRecentMenu.icon=file:resources/icons/open-recent.png
+ExportMenu.icon=file:resources/icons/export.png
+
+# Preferences Dialog
+PrefsDialog.title=Preferences
+PrefsDialog.application=Application
+PrefsDialog.status=Status Area
+PrefsDialog.view=View Preferences
+PrefsDialog.experiment=Experiment Mode
+PrefsDialog.general.tab=General
+PrefsDialog.close.text=&Close
+PrefsDialog.reset.text=&Reset
+PrefsDialog.enable-feedback.text=Show position and color in the status area
+PrefsDialog.foreground-color.text=Foreground color for markup
+PrefsDialog.background-color.text=Background color for markup
+PrefsDialog.experiment-embedded.text=Show experiment panel embedded in main window
+PrefsDialog.confirm-exit.text=Confirm exit when application is closed
+
+# Experiment Panel
+ExperimentPanel.description.title=Task Description 
+ExperimentPanel.timeout-message=The time allocated for this task is up!
+ExperimentPanel.experiment-complete-message=The experiment has been completed
+ExperimentPanel.button.text.start=Start
+ExperimentPanel.button.text.finish=Finish
diff --git a/image_annotation/resources/config/application.properties b/image_annotation/resources/config/application.properties
new file mode 100644 (file)
index 0000000..d21c608
--- /dev/null
@@ -0,0 +1,27 @@
+
+AppRecentMenu.icon=file:resources/icons/open-recent.png
+ExportMenu.icon=file:resources/icons/export.png
+
+# Preferences Dialog
+PrefsDialog.title=Preferences
+PrefsDialog.application=Application
+PrefsDialog.status=Status Area
+PrefsDialog.view=View Preferences
+PrefsDialog.experiment=Experiment Mode
+PrefsDialog.general.tab=General
+PrefsDialog.close.text=&Close
+PrefsDialog.close.icon=file:resources/icons/close.png
+PrefsDialog.reset.text=&Reset
+PrefsDialog.reset.icon=file:resources/icons/reset.png
+PrefsDialog.enable-feedback.text=Show position and color in the status area
+PrefsDialog.foreground-color.text=Foreground color for markup
+PrefsDialog.background-color.text=Background color for markup
+PrefsDialog.experiment-embedded.text=Show experiment panel embedded in main window
+PrefsDialog.confirm-exit.text=Confirm exit when application is closed
+
+# Experiment Panel
+ExperimentPanel.description.title=Task Description 
+ExperimentPanel.timeout-message=The time allocated for this task is up!
+ExperimentPanel.experiment-complete-message=The experiment has been completed
+ExperimentPanel.button.text.start=Start
+ExperimentPanel.button.text.finish=Finish
diff --git a/image_annotation/resources/config/view.properties b/image_annotation/resources/config/view.properties
new file mode 100644 (file)
index 0000000..73be3a2
--- /dev/null
@@ -0,0 +1,49 @@
+SegmentationView.Action.Foreground.text=Markup Foreground
+SegmentationView.Action.Foreground.tooltip=Markup Foreground Pixels
+SegmentationView.Action.Foreground.image=file:resources/icons/foreground.png
+SegmentationView.Action.Background.text=Markup Background
+SegmentationView.Action.Background.tooltip=Markup Background Pixels
+SegmentationView.Action.Background.image=file:resources/icons/background.png
+SegmentationView.Action.ZoomIn.text=Zoom In
+SegmentationView.Action.ZoomIn.tooltip=Zoom In
+SegmentationView.Action.ZoomIn.image=file:resources/icons/zoom-in.png
+SegmentationView.Action.ZoomOut.text=Zoom Out
+SegmentationView.Action.ZoomOut.tooltip=Zoom Out
+SegmentationView.Action.ZoomOut.image=file:resources/icons/zoom-out.png
+SegmentationView.Action.ZoomOriginal.text=Zoom Original
+SegmentationView.Action.ZoomOriginal.tooltip=Zoom to Original Size
+SegmentationView.Action.ZoomOriginal.image=file:resources/icons/zoom-original.png
+SegmentationView.Action.ZoomBestFit.text=Zoom Best Fit
+SegmentationView.Action.ZoomBestFit.tooltip=Zoom to Best Fit
+SegmentationView.Action.ZoomBestFit.image=file:resources/icons/zoom-best-fit.png
+SegmentationView.Action.Repaint.text=Refresh
+SegmentationView.Action.Repaint.tooltip=Refresh and repaint view
+SegmentationView.Action.Repaint.image=file:resources/icons/refresh.png
+SegmentationView.Action.Undo.text=&Undo@Ctrl+Z
+SegmentationView.Action.Undo.tooltip=Undo last markup
+SegmentationView.Action.Undo.image=file:resources/icons/undo.png
+SegmentationView.Action.Redo.text=&Redo@Ctrl+Y
+SegmentationView.Action.Redo.tooltip=Redo markup
+SegmentationView.Action.Redo.image=file:resources/icons/redo.png
+SegmentationView.Action.Clear.text=&Clear@Ctrl+DELETE
+SegmentationView.Action.Clear.tooltip=Clear all markup
+SegmentationView.Action.Clear.image=file:resources/icons/clear.png
+SegmentationView.Action.SetBrushSize.text=Set &Brush@Ctrl+B
+SegmentationView.Action.SetBrushSize.tooltip=Set the markup brush size
+SegmentationView.Action.SetBrushSize.image=file:resources/icons/brush.png
+SegmentationView.Action.AutoApply.text=Auto Segment@Ctrl+Shift+A
+SegmentationView.Action.AutoApply.tooltip=Toggle auto segment
+SegmentationView.Action.AutoApply.image=file:resources/icons/auto.png
+SegmentationView.Action.Apply.text=Segment@Ctrl+Shift+S
+SegmentationView.Action.Apply.tooltip=Apply new markup now
+SegmentationView.Action.Apply.image=file:resources/icons/apply.png
+SegmentationView.Action.SetPainter.text=View :
+SegmentationView.Action.SetPainter.tooltip=Select how to view the image/segmentation.
+SegmentationView.Action.SetPainter.image=
+SegmentationView.Action.SegmenterOptions.text=Configure Segmenter@Ctrl+Shift+C
+SegmentationView.Action.SegmenterOptions.tooltip=Configure the segmenter
+SegmentationView.Action.SegmenterOptions.image=file:resources/icons/preferences.png
+SegmentationView.Action.SetLabel.text=Annotate :
+SegmentationView.Action.SetLabel.tooltip=Annotate the segmented piece.
+SegmentationView.Action.SetLabel.image=
+
diff --git a/image_annotation/resources/doc/help.html b/image_annotation/resources/doc/help.html
new file mode 100644 (file)
index 0000000..44a573f
--- /dev/null
@@ -0,0 +1,169 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Interactive Segmentation Tool - User Guide</title><style type="text/css">
+.guicommand {
+  font-family: "Courier New",Courier,monospace;
+  font-weight: normal;
+  color: #990100;
+}
+.guishortcut {
+  font-family: "Courier New",Courier,monospace;
+  color: #666666;
+  font-style: italic;
+}
+.section {
+  font-weight: bold;
+  color: #404040;
+}
+.all {
+  margin: 0px;
+  padding: 10px 15px 50px;
+  background-color: white;
+}
+body {
+  margin: 0px 10px;
+  padding: 0px;
+  border-right-width: 1px;
+  border-left-width: 1px;
+  font-family: Arial,Helvetica,sans-serif;
+  border-right-style: dotted;
+  border-left-style: dotted;
+  background-color: #eff0ea;
+}
+h1 {
+  margin: 0px;
+  border-bottom-style: solid;
+  border-bottom-width: 1px;
+  padding-top: 10px;
+  padding-bottom: 15px;
+  text-align: center;
+  color: #404040;
+}
+h2 {
+  text-align: center;
+  color: #404040;
+}
+h3 {
+  color: #404040;
+}
+li {
+  padding-bottom: 10px;
+}
+.footer {
+  font-size: x-small;
+  text-align: center;
+}
+
+</style></head>
+<body>
+<div class="all">
+<h1>Interactive Segmentation Tool</h1>
+<h2>User Guide</h2>
+<h3>Usage</h3>
+In this section I will outline how to perform typical operations using
+the tool, such as opening images, extracting objects and exporting
+segmentation masks.<br>
+<br>
+<span class="section">Open an Image</span>&nbsp;<br>
+To open an image, select <span class="guicommand">File-&gt;Open</span><span class="guishortcut"></span>. Recently open files can
+be accessed using the <span class="guicommand">File-&gt;Open
+Recent</span> menu. Alternatively, an image file can be dragged
+from your file system and dropped into the application to open it.
+Currently images of type JPEG, PNG, GIF, and BMP are supported.<br>
+<br>
+<span class="section">Select a Segmenter</span><br>
+There are several different segmenters available in the tool. These can
+be selected from the <span class="guicommand">Tools</span>
+menu<span class="guicommand"></span>. To select one,
+click on it.<br>
+<br>
+<span class="section">Segmenting the Image&nbsp;</span><br class="section">
+Once you have an image open and a segmenter selected, you can segment
+the image by drawing scribbles on the image. First, move the mouse over
+the object you want to extract. Left click and drag inside the object
+to draw some scribbles inside the object. Now, move the mouse outside
+the object to some background pixels. Using the right mouse button,
+scribble outside the object to select some background. If using Mac
+OSX, or if you do not have a right mouse button (Graphics Tablet etc),
+you can use <span style="font-family: monospace;">Ctrl</span>
+and click instead of right click.<br>
+<br>
+The image will be segmented and the foreground will be brightened and
+the background darkened. If you are not happy with the segmentation,
+you can add more foreground and background scribbles.<br>
+<br>
+<span class="section">Undo, Redo and Clear</span><br>
+If you make a mistake, it can be undone by selecting <span class="guicommand">Edit-&gt;Undo</span><span style="font-weight: bold;"><span style="font-weight: bold;"></span> </span>or
+clicking the undo <img style="width: 16px; height: 16px;" alt="Undo Button" src="icons/undo.png"> button in the
+toolbar. To redo, select <span class="guicommand">Edit-&gt;Redo&nbsp;</span><span style="font-weight: bold;"></span>or click the
+redo&nbsp;<img style="width: 16px; height: 16px;" alt="Redo Button" src="icons/redo.png"> button. To
+remove all forground and background markup, click on the clear&nbsp;<img style="width: 16px; height: 16px;" alt="Clear Button" src="icons/reset.png"> button in the toolbar.<br>
+<br>
+<span class="section">Zooming</span><br>
+To get a closer look at&nbsp;the image, the toolbar can also be
+used to zoom-in on the image. To zoom-in by 10% use the <img style="width: 16px; height: 16px;" alt="Zoom In" src="icons/zoom-in.png"> button. To zoom-out by 10% use
+the&nbsp;<img style="width: 16px; height: 16px;" alt="Zoom Out" src="icons/zoom-out.png"> button. To
+zoom the image such that it fits into the window without needing
+scrollbars, use the <img style="width: 16px; height: 16px;" alt="Zoom Best Fit" src="icons/zoom-best-fit.png">
+button. To restore the image to its original size use the <img style="width: 16px; height: 16px;" alt="Zoom Original" src="icons/zoom-original.png"> button.<br>
+<br>
+<span class="section">Brush Size</span><br>
+To change the brush size, use the <img style="width: 16px; height: 16px;" alt="Paintbrush" src="icons/brush.png"> button to show the brush size
+chooser. It is often useful to use a bigger brush to make markings more
+visible or to quickly mark up more pixels.<br>
+<br>
+<span class="section">Views</span><br>
+It is sometimes useful to view the segmentation results in different
+ways. The default selected view is called "Combined" and shows the
+image, it's segmentation highlighted and the scribbles all overlayed on
+the same image. By using the drop down menu, you can select a different
+view:<br>
+<ul>
+<li><span style="font-style: italic;">Combined</span>:
+Shows the image with foreground areas brightened and background areas
+darkened. The foreground and background scribbles are overlayed.</li>
+<li><span style="font-style: italic;">Original:</span>
+Shows the original image, without any segmentation or scribbles
+overlayed.</li>
+<li><span style="font-style: italic;">Markup:</span>
+Shows only the foreground and background markup (scribbles).</li>
+<li><span style="font-style: italic;">Mask:</span>
+Shows the segmentation mask. That is, an image such that the foreground
+area is completely white and the background area completely black.</li>
+<li><span style="font-style: italic;">Foreground
+Only:</span> Removes all background elements and displays only
+the foreground object.</li>
+<li><span style="font-style: italic;">Outline
+Overlayed: </span>Displays and outline of the object overlayed
+onto the original image.</li>
+</ul>
+<strong>Note:</strong><span style="font-weight: bold;">
+</span>Only the combined view displays the foreground and
+background markup (scribbles). So if you are wondering where the
+scribbles disappeared to, select the combined view to make them visible.<br>
+<br class="section">
+<span class="section">Saving and Exporting</span><br>
+To save an work in progress segmentation, select <span class="guicommand">File-&gt;Save</span> or <span class="guicommand">File-&gt;Save As</span>. This
+will save the current segmentation and markup as a context file (<span style="font-family: monospace;">.ctx</span>). When
+finished segmenting an image, you may want to export the view as an
+image. To export the current view select <span class="guicommand">File-&gt;Export</span>.
+For example, if you wanted to save the segmentation mask, select the
+mask view and then <span class="guicommand">File-&gt;Export</span>.
+<br>
+<br class="section">
+<span class="section">Configuring a Segmenter</span><br>
+Some segmenters have parameters and options that can are configurable.
+To configure the selected segmenter, select <span class="guicommand">Tools-&gt;Configure
+Segmenter</span>, or click the <img style="width: 16px; height: 16px;" alt="Configure" src="icons/configure.png"> button in the toolbar.<br>
+<br class="section">
+<span class="section">Navigating Directories of Images</span><br>
+To quickly jump to the next or previous image in the current directory
+(the one containing the open image), use the <span class="guicommand">Go-&gt;Next</span> and <span class="guicommand">Go-&gt;Previous</span> menu
+items.<br>
+<br>
+<span class="section">Experiments</span><br class="section">
+Experiment files can be opened using the <span class="guicommand">Tools-&gt;Open
+Experiment</span> menu item.<br><br><br>
+<div class="footer">Kevin McGuinness 2008
+</div>
+</div>
+</body></html>
\ No newline at end of file
diff --git a/image_annotation/resources/icons/about-box.png b/image_annotation/resources/icons/about-box.png
new file mode 100644 (file)
index 0000000..3cd2db6
Binary files /dev/null and b/image_annotation/resources/icons/about-box.png differ
diff --git a/image_annotation/resources/icons/about.png b/image_annotation/resources/icons/about.png
new file mode 100644 (file)
index 0000000..3b8a885
Binary files /dev/null and b/image_annotation/resources/icons/about.png differ
diff --git a/image_annotation/resources/icons/application.png b/image_annotation/resources/icons/application.png
new file mode 100644 (file)
index 0000000..ca883da
Binary files /dev/null and b/image_annotation/resources/icons/application.png differ
diff --git a/image_annotation/resources/icons/apply.png b/image_annotation/resources/icons/apply.png
new file mode 100644 (file)
index 0000000..d7b5c2b
Binary files /dev/null and b/image_annotation/resources/icons/apply.png differ
diff --git a/image_annotation/resources/icons/auto.png b/image_annotation/resources/icons/auto.png
new file mode 100644 (file)
index 0000000..a3e8c31
Binary files /dev/null and b/image_annotation/resources/icons/auto.png differ
diff --git a/image_annotation/resources/icons/background.png b/image_annotation/resources/icons/background.png
new file mode 100644 (file)
index 0000000..0e633a3
Binary files /dev/null and b/image_annotation/resources/icons/background.png differ
diff --git a/image_annotation/resources/icons/brush.png b/image_annotation/resources/icons/brush.png
new file mode 100644 (file)
index 0000000..4bb955f
Binary files /dev/null and b/image_annotation/resources/icons/brush.png differ
diff --git a/image_annotation/resources/icons/clear.png b/image_annotation/resources/icons/clear.png
new file mode 100644 (file)
index 0000000..1556dfe
Binary files /dev/null and b/image_annotation/resources/icons/clear.png differ
diff --git a/image_annotation/resources/icons/close.png b/image_annotation/resources/icons/close.png
new file mode 100644 (file)
index 0000000..78b931f
Binary files /dev/null and b/image_annotation/resources/icons/close.png differ
diff --git a/image_annotation/resources/icons/copy.png b/image_annotation/resources/icons/copy.png
new file mode 100644 (file)
index 0000000..585579a
Binary files /dev/null and b/image_annotation/resources/icons/copy.png differ
diff --git a/image_annotation/resources/icons/dialog-error.png b/image_annotation/resources/icons/dialog-error.png
new file mode 100644 (file)
index 0000000..c2d0bb7
Binary files /dev/null and b/image_annotation/resources/icons/dialog-error.png differ
diff --git a/image_annotation/resources/icons/dialog-information.png b/image_annotation/resources/icons/dialog-information.png
new file mode 100644 (file)
index 0000000..23824bb
Binary files /dev/null and b/image_annotation/resources/icons/dialog-information.png differ
diff --git a/image_annotation/resources/icons/dialog-warning.png b/image_annotation/resources/icons/dialog-warning.png
new file mode 100644 (file)
index 0000000..06148e8
Binary files /dev/null and b/image_annotation/resources/icons/dialog-warning.png differ
diff --git a/image_annotation/resources/icons/exit.png b/image_annotation/resources/icons/exit.png
new file mode 100644 (file)
index 0000000..22a65a4
Binary files /dev/null and b/image_annotation/resources/icons/exit.png differ
diff --git a/image_annotation/resources/icons/experiment.png b/image_annotation/resources/icons/experiment.png
new file mode 100644 (file)
index 0000000..cb16a60
Binary files /dev/null and b/image_annotation/resources/icons/experiment.png differ
diff --git a/image_annotation/resources/icons/export.png b/image_annotation/resources/icons/export.png
new file mode 100644 (file)
index 0000000..f64425b
Binary files /dev/null and b/image_annotation/resources/icons/export.png differ
diff --git a/image_annotation/resources/icons/foreground.png b/image_annotation/resources/icons/foreground.png
new file mode 100644 (file)
index 0000000..4161f1d
Binary files /dev/null and b/image_annotation/resources/icons/foreground.png differ
diff --git a/image_annotation/resources/icons/help.png b/image_annotation/resources/icons/help.png
new file mode 100644 (file)
index 0000000..8542495
Binary files /dev/null and b/image_annotation/resources/icons/help.png differ
diff --git a/image_annotation/resources/icons/html.png b/image_annotation/resources/icons/html.png
new file mode 100644 (file)
index 0000000..d95fcc0
Binary files /dev/null and b/image_annotation/resources/icons/html.png differ
diff --git a/image_annotation/resources/icons/icon-16.png b/image_annotation/resources/icons/icon-16.png
new file mode 100644 (file)
index 0000000..b9e1264
Binary files /dev/null and b/image_annotation/resources/icons/icon-16.png differ
diff --git a/image_annotation/resources/icons/icon-24.png b/image_annotation/resources/icons/icon-24.png
new file mode 100644 (file)
index 0000000..7b93ba1
Binary files /dev/null and b/image_annotation/resources/icons/icon-24.png differ
diff --git a/image_annotation/resources/icons/icon-32.png b/image_annotation/resources/icons/icon-32.png
new file mode 100644 (file)
index 0000000..4bc8f32
Binary files /dev/null and b/image_annotation/resources/icons/icon-32.png differ
diff --git a/image_annotation/resources/icons/icon-48.png b/image_annotation/resources/icons/icon-48.png
new file mode 100644 (file)
index 0000000..c3fca3e
Binary files /dev/null and b/image_annotation/resources/icons/icon-48.png differ
diff --git a/image_annotation/resources/icons/image.png b/image_annotation/resources/icons/image.png
new file mode 100644 (file)
index 0000000..247ccad
Binary files /dev/null and b/image_annotation/resources/icons/image.png differ
diff --git a/image_annotation/resources/icons/next.png b/image_annotation/resources/icons/next.png
new file mode 100644 (file)
index 0000000..0011e67
Binary files /dev/null and b/image_annotation/resources/icons/next.png differ
diff --git a/image_annotation/resources/icons/open-recent.png b/image_annotation/resources/icons/open-recent.png
new file mode 100644 (file)
index 0000000..07cca3f
Binary files /dev/null and b/image_annotation/resources/icons/open-recent.png differ
diff --git a/image_annotation/resources/icons/open.png b/image_annotation/resources/icons/open.png
new file mode 100644 (file)
index 0000000..c3bcfcd
Binary files /dev/null and b/image_annotation/resources/icons/open.png differ
diff --git a/image_annotation/resources/icons/preferences.png b/image_annotation/resources/icons/preferences.png
new file mode 100644 (file)
index 0000000..e460eab
Binary files /dev/null and b/image_annotation/resources/icons/preferences.png differ
diff --git a/image_annotation/resources/icons/previous.png b/image_annotation/resources/icons/previous.png
new file mode 100644 (file)
index 0000000..d3bc514
Binary files /dev/null and b/image_annotation/resources/icons/previous.png differ
diff --git a/image_annotation/resources/icons/print.png b/image_annotation/resources/icons/print.png
new file mode 100644 (file)
index 0000000..2f1a0ff
Binary files /dev/null and b/image_annotation/resources/icons/print.png differ
diff --git a/image_annotation/resources/icons/redo.png b/image_annotation/resources/icons/redo.png
new file mode 100644 (file)
index 0000000..57de992
Binary files /dev/null and b/image_annotation/resources/icons/redo.png differ
diff --git a/image_annotation/resources/icons/refresh.png b/image_annotation/resources/icons/refresh.png
new file mode 100644 (file)
index 0000000..e46da27
Binary files /dev/null and b/image_annotation/resources/icons/refresh.png differ
diff --git a/image_annotation/resources/icons/reset.png b/image_annotation/resources/icons/reset.png
new file mode 100644 (file)
index 0000000..1556dfe
Binary files /dev/null and b/image_annotation/resources/icons/reset.png differ
diff --git a/image_annotation/resources/icons/run.png b/image_annotation/resources/icons/run.png
new file mode 100644 (file)
index 0000000..9010e7a
Binary files /dev/null and b/image_annotation/resources/icons/run.png differ
diff --git a/image_annotation/resources/icons/save-as.png b/image_annotation/resources/icons/save-as.png
new file mode 100644 (file)
index 0000000..a838052
Binary files /dev/null and b/image_annotation/resources/icons/save-as.png differ
diff --git a/image_annotation/resources/icons/save.png b/image_annotation/resources/icons/save.png
new file mode 100644 (file)
index 0000000..7da1d7c
Binary files /dev/null and b/image_annotation/resources/icons/save.png differ
diff --git a/image_annotation/resources/icons/undo.png b/image_annotation/resources/icons/undo.png
new file mode 100644 (file)
index 0000000..48db6f2
Binary files /dev/null and b/image_annotation/resources/icons/undo.png differ
diff --git a/image_annotation/resources/icons/view.png b/image_annotation/resources/icons/view.png
new file mode 100644 (file)
index 0000000..68da502
Binary files /dev/null and b/image_annotation/resources/icons/view.png differ
diff --git a/image_annotation/resources/icons/zoom-best-fit.png b/image_annotation/resources/icons/zoom-best-fit.png
new file mode 100644 (file)
index 0000000..eb28409
Binary files /dev/null and b/image_annotation/resources/icons/zoom-best-fit.png differ
diff --git a/image_annotation/resources/icons/zoom-in.png b/image_annotation/resources/icons/zoom-in.png
new file mode 100644 (file)
index 0000000..31ac736
Binary files /dev/null and b/image_annotation/resources/icons/zoom-in.png differ
diff --git a/image_annotation/resources/icons/zoom-original.png b/image_annotation/resources/icons/zoom-original.png
new file mode 100644 (file)
index 0000000..8e35414
Binary files /dev/null and b/image_annotation/resources/icons/zoom-original.png differ
diff --git a/image_annotation/resources/icons/zoom-out.png b/image_annotation/resources/icons/zoom-out.png
new file mode 100644 (file)
index 0000000..df5be3c
Binary files /dev/null and b/image_annotation/resources/icons/zoom-out.png differ
diff --git a/image_annotation/resources/plaf/debian/changelog b/image_annotation/resources/plaf/debian/changelog
new file mode 100644 (file)
index 0000000..7036b2c
--- /dev/null
@@ -0,0 +1,169 @@
+ist (1.3.4-1) stable; urgency=low
+
+  * Support for Mac OS X leopard (64 bit JVM)
+  
+  * Fixed bug in transparent PNG export on Windows platforms
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Thur, 27 Mar 2010 19:10:00 +0000
+
+ist (1.3.3-1) stable; urgency=low
+
+  * Updated API documentation
+
+  * Larger dialog for segmenter options
+
+  * Linux plugin builds now use GCC-4.1 for better compatibility
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Wed, 7 Oct 2009 19:00:00 +0000
+
+ist (1.3.2-1) stable; urgency=low
+
+  * Moved more components to the API layer. This includes painters and the image
+    control. This allows other apps to share core components.
+    
+  * Added export transparent PNG option
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Wed, 7 Oct 2009 18:00:00 +0000
+
+ist (1.3.1-1) stable; urgency=low
+
+  * Updated export HTML feature to export XHTML
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Wed, 2 Sep 2009 18:00:00 +0000
+
+ist (1.3.0-1) stable; urgency=low
+
+  * Major restructuring of application to ease plugin development
+  
+  * New version of SWT
+  
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Mon, 24 Aug 2009 18:00:00 +0000
+
+ist (1.2.5-1) stable; urgency=low
+
+  * Added code for automated evaluation
+  
+  * Update man page and run templates
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Mon, 9 Mar 2009 16:21:00 +0000
+
+ist (1.2.4-1) stable; urgency=medium
+
+  * Fixed erratic behavior of SIOX segmenter
+  
+  * Added a lot of code for automated evaluation
+  
+  * Added option to force segmenters to retain all markup pixels in mask.
+  
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Fri, 23 Jan 2009 18:00:00 +0000
+ist (1.2.3-1) stable; urgency=medium
+
+  * Fixed redo bug (redo was calling undo)
+  
+  * Segmentation context does not create an Image unless asked to now. This
+    prevents it initializing the swt Display object unless it needs to, allowing
+    console applications that use the core segmentation stuff to be created
+    without initializing the Display.
+  
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Thu, 8 Jan 2009 15:00:00 +0000
+
+ist (1.2.2-1) stable; urgency=low
+
+  * Fixed application name in menu bar on OS X
+  
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Tue, 6 Jan 2009 15:00:00 +0000
+
+ist (1.2.1-1) stable; urgency=low
+
+  * Use command key instead of ctrl key for shortcuts on Mac OSX
+  
+  * Zip file for app bundle on OS X: it's better supported than tar.gz
+  
+  * Modified about box to display SWT version
+  
+  * Added standard Command+, binding for preferences on Mac
+  
+  * Use small icons in menus on all platforms
+  
+  * Removed icons in preference dialog buttons on Mac OS
+  
+  * Improved and included several new icons
+  
+  * Fixed visual bug on linux: horizontal separators didn't look right in
+    the export dialog.
+  
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Wed, 17 Dec 2008 17:00:00 +0000
+
+ist (1.2.0-1) stable; urgency=low
+  
+  * New feature: export to HTML image maps integrated. Supports exporting 
+    polygons and rectangles for now. Can export several rollover effects using 
+    the javascript image swapping technique.
+    
+  * Fixed bug on Mac OS X: application did not always exit properly
+  
+  * Open browser window to show the HTML page when export completes
+  
+  * Option to turn on or off the open browser window behavior
+  
+  * Best practices: use var for global image preloads.
+    
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Tue, 16 Dec 2008 21:37:00 +0000
+
+ist (1.1.0-1) stable; urgency=low
+  
+  * Several new features are planned for introduction, so the version number
+    has been incremented to 1.1
+  
+  * Changed context file format. This is now stored as a zip archive including 
+    the image, mask and annotations, so that it is more "self-contained". The
+    new file format is NOT compatible with the old one.
+    
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Tue, 29 Feb 2008 12:25:00 +0000
+
+ist (1.0.6-1) stable; urgency=low
+
+  * Added startup check for gdiplus.dll for platforms where it's needed but not 
+    installed by default. Program will now show a useful message and exit gracefully
+    instead of spewing stack traces on the console and behaving oddly.
+    
+  * Fixed bug that caused the auto-apply toggle button to be always disabled
+    after first image load.
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Tue, 28 Feb 2008 10:36:00 +0000
+
+ist (1.0.5-1) stable; urgency=medium
+
+  * Fixed bug that caused the brush control (and some other toolbar buttons) to be
+    disabled after an experiment was cancelled.
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Tue, 12 Feb 2008 13:25:00 +0000
+ist (1.0.4-1) stable; urgency=low
+
+  * Updated the integrated help file (help.html)
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Tue, 28 Jan 2008 16:40:00 +0000
+
+ist (1.0.3-1) stable; urgency=low
+
+  * MacOSX PowerPC now supported
+
+  * Mostly non-functional changes on Linux, refactoring and the like
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Tue, 25 Jan 2008 16:08:00 +0000
+
+ist (1.0.2-1) stable; urgency=low
+
+  * Application icon added
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Tue, 16 Jan 2008 19:43:00 +0000
+
+ist (1.0.1-1) stable; urgency=low
+
+  * Created debian package
+  
+  * Support added for 64 bit linux
+
+ -- Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>  Tue, 15 Jan 2008 19:43:00 +0000
diff --git a/image_annotation/resources/plaf/debian/copyright b/image_annotation/resources/plaf/debian/copyright
new file mode 100644 (file)
index 0000000..32da294
--- /dev/null
@@ -0,0 +1,10 @@
+ist
+
+Copyright: Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>
+           Center for Digital Video Processing
+           Dublin City University
+
+2008-01-14
+
+The home page of ist is at: 
+https://www.kspace.cdvp.dcu.ie/public/interactive-segmentation
diff --git a/image_annotation/resources/plaf/debian/desktop b/image_annotation/resources/plaf/debian/desktop
new file mode 100644 (file)
index 0000000..718ced1
--- /dev/null
@@ -0,0 +1,10 @@
+# freedesktop.org desktop entry
+[Desktop Entry]
+Version=1.0
+Type=Application
+Name=Interactive Segmentation Tool
+Comment=Interactively extract objects from images using various algorithms
+Icon=ist
+Exec=ist
+Terminal=false
+Categories=GTK;Graphics
diff --git a/image_annotation/resources/plaf/debian/ist b/image_annotation/resources/plaf/debian/ist
new file mode 100644 (file)
index 0000000..d1e385d
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+# Setup
+data=@data@
+main=@main@
+jars=@jars@
+
+# Change directory
+cd "${data}"
+
+# This is needed for the browser widget on linux
+if [ -z "${MOZILLA_FIVE_HOME}" ]; then
+       # Check if common locations exist
+       if [ -d "/usr/lib/firefox" ]; then
+               export MOZILLA_FIVE_HOME=/usr/lib/firefox
+       elif [ -d "/usr/lib/mozilla-firefox" ]; then
+               export MOZILLA_FIVE_HOME=/usr/lib/mozilla-firefox
+       elif [ -d "/usr/lib/mozilla" ]; then
+               export MOZILLA_FIVE_HOME=/usr/lib/mozilla
+       fi
+fi
+
+# Set library path
+if [ -n "${MOZILLA_FIVE_HOME}" ]; then
+       export LD_LIBRARY_PATH=${MOZILLA_FIVE_HOME}:${LD_LIBRARY_PATH}
+fi
+
+# Launch
+if [ -n "${JAVA_HOME}" ]; then
+       ${JAVA_HOME}/bin/java -classpath "${jars}" ${main} $*
+else
+       java -classpath "${jars}" ${main} $*
+fi
+
+cd "$OLDPWD"
+
diff --git a/image_annotation/resources/plaf/debian/ist.1 b/image_annotation/resources/plaf/debian/ist.1
new file mode 100644 (file)
index 0000000..29faaf6
--- /dev/null
@@ -0,0 +1,29 @@
+.TH "ist" "1" "1.3.3" "Kevin McGuinness" "Graphics"
+.SH "NAME"
+.LP 
+ist \- Interactive Segmentation Tool
+.SH "SYNTAX"
+.LP 
+ist [options]
+
+.SH "DESCRIPTION"
+.LP 
+Launches the interactive segmentation tool graphical user interface
+
+.SH "ENVIRONMENT VARIABLES"
+.LP 
+.TP 
+\fBMOZILLA_FIVE_HOME\fP
+Specifies the location of the mozilla 5 browser 
+(firefox etc.). This is usually something like 
+/usr/lib/firefox
+
+.SH "EXAMPLES"
+.LP 
+To run this program the standard way type:
+.LP 
+$ ist
+
+.SH "AUTHORS"
+.LP 
+Kevin McGuinness <kevin.mcguinness@eeng.dcu.ie>
diff --git a/image_annotation/resources/plaf/debian/postinst b/image_annotation/resources/plaf/debian/postinst
new file mode 100644 (file)
index 0000000..fb29bea
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+sudo update-desktop-database
+sudo gtk-update-icon-cache /usr/share/icons/hicolor
diff --git a/image_annotation/resources/plaf/debian/postrm b/image_annotation/resources/plaf/debian/postrm
new file mode 100644 (file)
index 0000000..fb29bea
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+sudo update-desktop-database
+sudo gtk-update-icon-cache /usr/share/icons/hicolor
diff --git a/image_annotation/resources/plaf/linux/ist b/image_annotation/resources/plaf/linux/ist
new file mode 100644 (file)
index 0000000..1f45a3a
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+jars=istapp.jar:istapi.jar:swt.jar:jface.jar
+main=ie.dcu.apps.ist.Main
+
+# Change directory
+cd "`dirname "$0"`"
+
+# This is needed for the SWT browser widget on linux
+if [ -z "${MOZILLA_FIVE_HOME}" ]; then
+
+       # Check if common locations exist
+       if [ -d "/usr/lib/firefox" ]; then
+               export MOZILLA_FIVE_HOME=/usr/lib/firefox
+       elif [ -d "/usr/lib/mozilla-firefox" ]; then
+               export MOZILLA_FIVE_HOME=/usr/lib/mozilla-firefox
+       elif [ -d "/usr/lib/mozilla" ]; then
+               export MOZILLA_FIVE_HOME=/usr/lib/mozilla
+       fi
+       
+fi
+
+# Set library path
+if [ -n "${MOZILLA_FIVE_HOME}" ]; then
+       export LD_LIBRARY_PATH=${MOZILLA_FIVE_HOME}:${LD_LIBRARY_PATH}
+fi
+
+if [ -n "${JAVA_HOME}" ]; then
+       ${JAVA_HOME}/bin/java -classpath "${jars}"  ${main} $*
+else
+       java -classpath "${jars}" ${main} $*
+fi
+
+cd "$OLDPWD"
diff --git a/image_annotation/resources/plaf/mac/Info.plist b/image_annotation/resources/plaf/mac/Info.plist
new file mode 100644 (file)
index 0000000..0fbcac6
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
+                       "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+  <dict>
+    <key>CFBundleName</key>
+    <string>@name@</string>
+    <key>CFBundleShortVersionString</key>
+    <string>@version@</string>
+    <key>CFBundleGetInfoString</key>
+    <string>@synopsis@ (v@version@)</string>
+    <key>CFBundleAllowMixedLocalizations</key>
+    <string>false</string>
+    <key>CFBundleInfoDictionaryVersion</key>
+    <string>6.0</string>
+    <key>CFBundleExecutable</key>
+    <string>@exename@</string>
+    <key>CFBundleDevelopmentRegion</key>
+    <string>English</string>
+    <key>CFBundlePackageType</key>
+    <string>APPL</string>
+    <key>CFBundleSignature</key>
+    <string>????</string>
+    <key>CFBundleIconFile</key>
+    <string>@icons@</string>
+  </dict>
+</plist>
diff --git a/image_annotation/resources/plaf/mac/PkgInfo b/image_annotation/resources/plaf/mac/PkgInfo
new file mode 100644 (file)
index 0000000..6f749b0
--- /dev/null
@@ -0,0 +1 @@
+APPL????
diff --git a/image_annotation/resources/plaf/mac/icon.icns b/image_annotation/resources/plaf/mac/icon.icns
new file mode 100644 (file)
index 0000000..ae867d3
Binary files /dev/null and b/image_annotation/resources/plaf/mac/icon.icns differ
diff --git a/image_annotation/resources/plaf/mac/ist b/image_annotation/resources/plaf/mac/ist
new file mode 100644 (file)
index 0000000..07663d1
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# What kinda mac are we on
+CPU=`uname -p`
+
+# Absolute path to where the app was launched from
+APP_PACKAGE="`dirname "$0"`/../.."
+APP_PACKAGE="`cd "${APP_PACKAGE}"; pwd`"
+
+# Locations of resources, jars, and libs
+LIB_DIR="Libraries/${CPU}"
+
+# Move to the resource directory
+cd "${APP_PACKAGE}/Contents/Resources"
+
+# Establish whether we should use the 32 bit or 64 bit cocoa library
+SWT_LIBNAME=swt-cocoa-32.jar
+java -version 2>&1 | grep "64-Bit" > /dev/null
+if [ "$?" -eq "0" ]; then
+       SWT_LIBNAME=swt-cocoa-64.jar
+fi
+
+echo "SWT Library: ${SWT_LIBNAME}"
+
+# Launch app
+java \
+  -XstartOnFirstThread \
+  -classpath "Java/istapp.jar:Java/istapi.jar:Java/jface.jar:Java/${SWT_LIBNAME}" \
+  -Dorg.eclipse.swt.internal.carbon.noFocusRing \
+  -Dorg.eclipse.swt.internal.carbon.smallFonts \
+  @appmain@ $*
+
+# Go back to the old working directory
+cd "${OLDPWD}"
diff --git a/image_annotation/resources/plaf/windows/application.ico b/image_annotation/resources/plaf/windows/application.ico
new file mode 100644 (file)
index 0000000..ae1ac33
Binary files /dev/null and b/image_annotation/resources/plaf/windows/application.ico differ
diff --git a/image_annotation/resources/plaf/windows/install.xml b/image_annotation/resources/plaf/windows/install.xml
new file mode 100644 (file)
index 0000000..23cb85e
--- /dev/null
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
+
+<!-- 
+    IzPack install file for the Interactive Segmentation Tool
+-->
+
+<installation version="1.0">
+
+    <!-- The info section. -->
+    <info>
+        <appname>@name@</appname>
+        <appversion>@version@</appversion>
+        <authors>
+            <author name="@author@" email="@email@"/>
+        </authors>
+        <url>@website@</url>
+        <javaversion>1.5</javaversion>
+    </info>
+
+    <!-- The gui preferences indication. -->
+    <guiprefs width="640" height="480" resizable="no"/>
+
+    <!-- The locale section. -->
+    <locale>
+        <langpack iso3="eng"/>
+    </locale>
+
+    <!-- The resources section. -->
+    <resources>
+        <res src="resources/plaf/windows/shortcuts.xml" id="shortcutSpec.xml"/>
+    </resources>
+
+    <!-- Shell-link for windows. -->
+    <native type="izpack" name="ShellLink.dll" />
+
+    <!-- The panels section. -->
+    <panels>
+        <panel classname="HelloPanel"/>
+        <panel classname="TargetPanel"/> 
+        <panel classname="PacksPanel"/>
+        <panel classname="InstallPanel"/>
+        <panel classname="ShortcutPanel"/>
+        <panel classname="FinishPanel"/>
+    </panels>
+
+    <!-- The packs section. -->
+    <packs>
+        <pack name="Base" required="yes">
+            <description> Base installation files </description>
+            <fileset dir="build/packages/windows" targetdir="${INSTALL_PATH}" >
+                <include name="**/*" />
+            </fileset>
+        </pack>
+    </packs>
+    
+</installation>
diff --git a/image_annotation/resources/plaf/windows/installer.ico b/image_annotation/resources/plaf/windows/installer.ico
new file mode 100644 (file)
index 0000000..66d530f
Binary files /dev/null and b/image_annotation/resources/plaf/windows/installer.ico differ
diff --git a/image_annotation/resources/plaf/windows/installer.jsmooth b/image_annotation/resources/plaf/windows/installer.jsmooth
new file mode 100644 (file)
index 0000000..823d035
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<jsmoothproject>
+    <JVMSearchPath>registry</JVMSearchPath>
+    <JVMSearchPath>javahome</JVMSearchPath>
+    <JVMSearchPath>jrepath</JVMSearchPath>
+    <JVMSearchPath>jdkpath</JVMSearchPath>
+    <JVMSearchPath>exepath</JVMSearchPath>
+    <JVMSearchPath>jview</JVMSearchPath>
+    <jarLocation>@input@</jarLocation>
+    <iconLocation>@icon@</iconLocation>
+    <currentDirectory>${EXECUTABLEPATH}</currentDirectory>
+    <embeddedJar>true</embeddedJar>
+    <executableName>@output@</executableName>
+    <initialMemoryHeap>-1</initialMemoryHeap>
+    <mainClassName>com.izforge.izpack.installer.Installer</mainClassName>
+    <maximumMemoryHeap>-1</maximumMemoryHeap>
+    <maximumVersion></maximumVersion>
+    <minimumVersion>1.5</minimumVersion>
+    <skeletonName>Windowed Wrapper</skeletonName>
+    <skeletonProperties>
+        <key>Message</key>
+        <value>Java has not been found on your computer.
+        Do you want to download it?</value>
+    </skeletonProperties>
+    <skeletonProperties>
+        <key>Debug</key>
+        <value>0</value>
+    </skeletonProperties>
+</jsmoothproject>
diff --git a/image_annotation/resources/plaf/windows/ist.jsmooth b/image_annotation/resources/plaf/windows/ist.jsmooth
new file mode 100644 (file)
index 0000000..52388f9
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<jsmoothproject>
+    <JVMSearchPath>registry</JVMSearchPath>
+    <JVMSearchPath>javahome</JVMSearchPath>
+    <JVMSearchPath>jrepath</JVMSearchPath>
+    <JVMSearchPath>jdkpath</JVMSearchPath>
+    <JVMSearchPath>exepath</JVMSearchPath>
+    <JVMSearchPath>jview</JVMSearchPath>
+    <classPath>istapp.jar</classPath>
+    <classPath>istapi.jar</classPath>
+    <classPath>swt-win.jar</classPath>
+    <classPath>jface.jar</classPath>
+    <currentDirectory>${EXECUTABLEPATH}</currentDirectory>
+    <embeddedJar>false</embeddedJar>
+    <executableName>ist.exe</executableName>
+    <iconLocation>application.ico</iconLocation>
+    <initialMemoryHeap>-1</initialMemoryHeap>
+    <mainClassName>ie.dcu.apps.ist.Main</mainClassName>
+    <maximumMemoryHeap>-1</maximumMemoryHeap>
+    <minimumVersion>1.5.0</minimumVersion>
+    <skeletonName>Windowed Wrapper</skeletonName>
+    <skeletonProperties>
+        <key>Message</key>
+        <value>This program needs Java to run.
+        Please download it at http://www.java.com</value>
+    </skeletonProperties>
+    <skeletonProperties>
+        <key>Debug</key>
+        <value>0</value>
+    </skeletonProperties>
+</jsmoothproject>
diff --git a/image_annotation/resources/plaf/windows/shortcuts.xml b/image_annotation/resources/plaf/windows/shortcuts.xml
new file mode 100644 (file)
index 0000000..d34c867
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\r
+<shortcuts>\r
+       <skipIfNotSupported/>\r
+       <programGroup defaultName="IST" location="applications"/>\r
+       \r
+       <shortcut\r
+               name="Interactive Segmentation Tool"\r
+               target="$INSTALL_PATH\ist.exe"\r
+               workingDirectory="$INSTALL_PATH"\r
+               description="Launch the Interactive Segmentation Tool"\r
+               initialState="normal"\r
+               programGroup="yes"\r
+               desktop="yes"\r
+               applications="no"\r
+               startMenu="no"\r
+               startup="no"\r
+       >\r
+               <createForPack name="Base"/>\r
+       </shortcut>\r
+\r
+       <shortcut\r
+               name="Uninstall"\r
+               target="${JAVA_HOME}\bin\java.exe"\r
+               commandLine="-jar &quot;$INSTALL_PATH/Uninstaller/uninstaller.jar&quot;"\r
+               description="Uninstall Interactive Segmentation Tool"\r
+               initialState="noShow"\r
+               programGroup="yes"\r
+               desktop="no"\r
+               applications="no"\r
+               startMenu="no"\r
+               startup="no"\r
+       >\r
+               <createForPack name="Base"/>\r
+       </shortcut>\r
+\r
+</shortcuts>\r
diff --git a/image_annotation/resources/plaf/windows/skeletons/windowed-wrapper/description.skel b/image_annotation/resources/plaf/windows/skeletons/windowed-wrapper/description.skel
new file mode 100644 (file)
index 0000000..52acb08
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<jsmoothskeleton>
+<debug>false</debug>
+<description>SKEL_SIMPLEWRAPPER_DESCRIPTION</description>
+<executableName>jwrap.exe</executableName>
+<resourceCategory>JAVA</resourceCategory>
+<resourceJarId>102</resourceJarId>
+<resourcePropsId>103</resourcePropsId>
+<shortName>Windowed Wrapper</shortName>
+<skeletonProperties>
+<description>SKEL_SIMPLEWRAPPER_PROPERTY_MESSAGE_DESCRIPTION</description>
+<idName>Message</idName>
+<label>SKEL_SIMPLEWRAPPER_PROPERTY_MESSAGE_LABEL</label>
+<type>textarea</type>
+<value>Java has not been found on your computer. Do you want to download it?</value>
+</skeletonProperties>
+<skeletonProperties>
+<description>SKEL_SIMPLEWRAPPER_PROPERTY_URL_DESCRIPTION</description>
+<idName>URL</idName>
+<label>SKEL_SIMPLEWRAPPER_PROPERTY_URL_LABEL</label>
+<type>string</type>
+<value>http://www.java.com</value>
+</skeletonProperties>
+<skeletonProperties>
+<description>SKEL_GENERIC_PROPERTY_SINGLEPROCESS_DESCRIPTION</description>
+<idName>SingleProcess</idName>
+<label>SKEL_GENERIC_PROPERTY_SINGLEPROCESS_LABEL</label>
+<type>boolean</type>
+<value>0</value>
+</skeletonProperties>
+<skeletonProperties>
+<description>SKEL_GENERIC_SINGLEINSTANCE_DESCRIPTION</description>
+<idName>SingleInstance</idName>
+<label>SKEL_GENERIC_SINGLEINSTANCE</label>
+<type>boolean</type>
+<value>0</value>
+</skeletonProperties>
+<skeletonProperties>
+<description>SKEL_GENERIC_JNISMOOTH_DESCRIPTION</description>
+<idName>JniSmooth</idName>
+<label>SKEL_GENERIC_JNISMOOTH</label>
+<type>boolean</type>
+<value>0</value>
+</skeletonProperties>
+<skeletonProperties>
+<description>SKEL_GENERIC_PROPERTY_DEBUG_DESCRIPTION</description>
+<idName>Debug</idName>
+<label>SKEL_GENERIC_PROPERTY_DEBUG_LABEL</label>
+<type>boolean</type>
+<value>0</value>
+</skeletonProperties>
+</jsmoothskeleton>
diff --git a/image_annotation/resources/plaf/windows/skeletons/windowed-wrapper/jwrap.exe b/image_annotation/resources/plaf/windows/skeletons/windowed-wrapper/jwrap.exe
new file mode 100755 (executable)
index 0000000..436402d
Binary files /dev/null and b/image_annotation/resources/plaf/windows/skeletons/windowed-wrapper/jwrap.exe differ
diff --git a/image_annotation/src/ie/dcu/apps/ist/AppPrefs.java b/image_annotation/src/ie/dcu/apps/ist/AppPrefs.java
new file mode 100644 (file)
index 0000000..fabc554
--- /dev/null
@@ -0,0 +1,259 @@
+package ie.dcu.apps.ist;
+
+import ie.dcu.swt.SwtUtils;
+
+import java.util.*;
+import java.util.logging.Logger;
+import java.util.prefs.*;
+
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Manages application preferences
+ * 
+ * @author Kevin McGuinness
+ */
+public class AppPrefs {
+       
+       public interface Keys {
+               public static final String ENABLE_FEEDBACK = "enable-feedback";
+               public static final String FOREGROUND_COLOR = "foreground-color";
+               public static final String BACKGROUND_COLOR = "background-color";
+               public static final String EXPERIMENT_EMBEDDED = "experiment-embedded";
+               public static final String CONFIRM_EXIT = "confirm-exit";
+       }
+       
+       public interface SupportedTypes {
+               public static final Class<Integer> INTEGER = Integer.class;
+               public static final Class<Double>  DOUBLE  = Double.class;
+               public static final Class<Float>   FLOAT   = Float.class;
+               public static final Class<Short>   SHORT   = Short.class;
+               public static final Class<Byte>    BYTE    = Byte.class;
+               public static final Class<Long>    LONG    = Long.class;
+               public static final Class<String>  STRING  = String.class;
+               public static final Class<Boolean> BOOLEAN = Boolean.class;
+               public static final Class<RGB>     RGB     = RGB.class;
+       }
+       
+       
+       private final Logger log;
+       private final Preferences prefs;
+       private final List<PreferenceChangeListener> listeners;
+
+       
+       public AppPrefs() {
+               this.log = Logger.getLogger(getClass().getName());
+               this.prefs = Preferences.userRoot().node(Application.APP_ID);
+               this.listeners = new LinkedList<PreferenceChangeListener>();
+               
+               addSwtThreadAdaptionListener();
+       }
+       
+       
+       private void addSwtThreadAdaptionListener() {
+               prefs.addPreferenceChangeListener(new PreferenceChangeListener() {
+                       public void preferenceChange(PreferenceChangeEvent evt) {
+                               firePreferenceChangedSynced(evt);
+                       }
+               });
+       }
+
+
+       private void firePreferenceChangedSynced(final PreferenceChangeEvent evt) {
+                       
+               // Delegate to event SWT event dispatching thread
+               Display.getDefault().syncExec(new Runnable() {
+                       public void run() {
+                               firePreferenceChanged(evt);     
+                       }
+               });
+       
+       }
+
+
+       private void firePreferenceChanged(PreferenceChangeEvent evt) {
+               for (PreferenceChangeListener listener : listeners) {
+                       listener.preferenceChange(evt);
+               }
+       }
+
+
+       public void sync() {
+               try {
+                       prefs.sync();
+               } catch (BackingStoreException e) {
+                       log.warning("Error syncing preferences: " + e.getMessage());
+               }
+       }
+       
+       
+       public void flush() {
+               try {
+                       prefs.flush();
+               } catch (BackingStoreException e) {
+                       log.warning("Error writing preferences: " + e.getMessage());
+               }
+       }
+       
+
+       public void clear() {
+               try {
+                       prefs.clear();
+               } catch (BackingStoreException e) {
+                       log.warning("Error clearing preferences: " + e.getMessage());
+               }
+       }
+
+
+       public String[] keys() {
+               try {
+                       return prefs.keys();
+               } catch (BackingStoreException e) {
+                       log.warning("Error retrieving preference keys: " + e.getMessage());
+               }
+               return new String[0];
+       }
+
+
+       public void remove(String key) {
+               prefs.remove(key);
+       }
+
+
+       public <T> T get(Class<T> clazz, String key, T def) {
+               String value =  (def != null) ? 
+                               get(key, def.toString()) : get(key, null);
+               
+               return decode(clazz, value, def);
+       }
+       
+
+       public <T> void put(Class<T> clazz, String key, T value) {
+               prefs.put(key, encode(clazz, value));
+       }
+       
+       
+       public void put(String key, String value) {
+               prefs.put(key, value);
+       }
+       
+       
+       public String get(String key, String def) {
+               return prefs.get(key, def);
+       }
+       
+       
+       public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
+               listeners.add(pcl);
+       }
+
+
+       public void removePreferenceChangeListener(PreferenceChangeListener pcl) {
+               listeners.remove(pcl);
+       }
+
+
+       public <T> String encode(Class<T> clazz, T value) {
+               if (clazz.equals(RGB.class)) {
+                       return encodeRGB((RGB) value);
+               } else if (value != null) {
+                       return String.valueOf(value);
+               } else {
+                       return null;
+               }
+       }
+       
+       
+       public <T> T decode(Class<T> clazz, String str, T def) {
+               if (str == null) {
+                       return def;
+               }       else if (isNumeric(clazz)) {
+                       return clazz.cast(decodeNumeric(clazz, str, def));
+               } else if (isString(clazz)) {
+                       return clazz.cast(str);
+               } else if (isBoolean(clazz)) {
+                       return clazz.cast(decodeBoolean(str, (Boolean) def));
+               } else if (clazz.equals(RGB.class)) {
+                       return clazz.cast(decodeRGB(str, (RGB) def));
+               } else {
+                       log.warning("Unable to decode class: " + clazz.getName());
+               }
+               
+               return def;
+       }
+       
+       
+       private boolean isString(Class<?> clazz) {
+               return clazz.equals(String.class);
+       }
+       
+       
+       private boolean isBoolean(Class<?> clazz) {
+               return clazz.equals(Boolean.class);
+       }
+       
+       
+       
+       private boolean isNumeric(Class<?> clazz) {
+               return 
+                       clazz.equals(Integer.class) ||
+                       clazz.equals(Double.class) ||
+                       clazz.equals(Float.class) ||
+                       clazz.equals(Short.class) ||
+                       clazz.equals(Byte.class) ||
+                       clazz.equals(Long.class);      
+       }
+       
+       
+       private RGB decodeRGB(String str, RGB def) {
+               if (str.startsWith("#")) {
+                       try {
+                               int hex = Integer.parseInt(str.substring(1), 16);
+                               return SwtUtils.int2rgb(hex);
+                       } catch (NumberFormatException e) {
+                               log.warning("Not a valid color: " + str);
+                       }
+               }
+               return def;
+       }
+       
+       
+       private String encodeRGB(RGB rgb) {
+               return String.format("#%06x", SwtUtils.rgb2int(rgb));
+       }
+       
+       
+       private boolean decodeBoolean(String str, boolean def) {
+               return str.equalsIgnoreCase("true") ||
+                       (str.equalsIgnoreCase("false") ? false : def);
+       }
+       
+       
+       private <T> T decodeNumeric(Class<T> clazz, String s, T def) {
+               try {
+                       if (clazz.equals(Integer.class)) {
+                               return clazz.cast(Integer.parseInt(s));
+                               
+                       } else if (clazz.equals(Double.class)) {
+                               return clazz.cast(Double.parseDouble(s));
+                       
+                       } else if (clazz.equals(Float.class)) {
+                               return clazz.cast(Float.parseFloat(s));
+                       
+                       } else if (clazz.equals(Short.class)) {
+                               return clazz.cast(Short.parseShort(s));
+                       
+                       } else if (clazz.equals(Byte.class)) {
+                               return clazz.cast(Byte.parseByte(s));
+                       
+                       } else if (clazz.equals(Long.class)) {
+                               return clazz.cast(Long.parseLong(s));
+                       
+                       }  
+               } catch (NumberFormatException ex) {
+                       log.warning("Invalid numeric value in preferences: " + s);
+               }
+               return def;
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/AppPrefsManager.java b/image_annotation/src/ie/dcu/apps/ist/AppPrefsManager.java
new file mode 100644 (file)
index 0000000..e41ea3b
--- /dev/null
@@ -0,0 +1,97 @@
+package ie.dcu.apps.ist;
+
+import static ie.dcu.segment.annotate.AnnotationType.*;
+import static ie.dcu.apps.ist.AppPrefs.Keys.*;
+import static ie.dcu.apps.ist.AppPrefs.SupportedTypes.*;
+import ie.dcu.segment.annotate.*;
+import ie.dcu.apps.ist.AppPrefs.*;
+
+import java.util.prefs.*;
+
+import org.eclipse.jface.resource.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Manages updating various components when preferences change.
+ * 
+ * @author Kevin McGuinness
+ */
+class AppPrefsManager implements PreferenceChangeListener {
+       
+       private final AppWindow window;
+       private final ColorRegistry colorRegistry;
+       private final AppPrefs prefs;
+       
+
+       public AppPrefsManager(AppWindow window) {
+               this.window = window;
+               this.colorRegistry = JFaceResources.getColorRegistry();
+               this.prefs = loadPreferences();
+       }
+       
+       
+       private AppPrefs loadPreferences() {
+               AppPrefs prefs = new AppPrefs();
+               prefs.addPreferenceChangeListener(this);
+               return prefs;
+       }
+       
+       
+       public AppPrefs getPrefs() {
+               return prefs;
+       }
+       
+       
+       public void update() {
+               updateFeedbackEnabled();
+               updateBackgroundColor();
+               updateForegroundColor();
+               updateExperimentEmbedded();
+       }
+       
+       
+       public void updateExperimentEmbedded() {
+               boolean on = prefs.get(BOOLEAN, Keys.EXPERIMENT_EMBEDDED, false);
+               window.setExperimentModeEmbedded(on);
+       }
+       
+       
+       public void updateFeedbackEnabled() {
+               boolean on = prefs.get(BOOLEAN, Keys.ENABLE_FEEDBACK, true);
+               window.setEnableFeedback(on);
+       }
+       
+       
+       public void updateForegroundColor() {
+               RGB color = prefs.get(RGB, Keys.FOREGROUND_COLOR, DEFAULT_FOREGROUND);
+               colorRegistry.put(AnnotationType.Foreground.key, color);
+               window.getView().repaint();
+       }
+       
+       
+       public void updateBackgroundColor() {
+               RGB color = prefs.get(RGB, Keys.BACKGROUND_COLOR, DEFAULT_BACKGROUND);
+               colorRegistry.put(AnnotationType.Background.key, color);
+               window.getView().repaint();
+       }
+       
+
+       public void preferenceChange(PreferenceChangeEvent evt) {
+               String pref = evt.getKey();
+               
+               if (pref.equals(ENABLE_FEEDBACK)) {
+                       updateFeedbackEnabled();
+               
+               } else if (pref.equals(FOREGROUND_COLOR)) {
+                       updateForegroundColor();
+               
+               } else if (pref.equals(BACKGROUND_COLOR)) {
+                       updateBackgroundColor();
+                       
+               } else if (pref.equals(EXPERIMENT_EMBEDDED)) {
+                       updateExperimentEmbedded();
+               }
+
+       }
+
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/AppRecentFiles.java b/image_annotation/src/ie/dcu/apps/ist/AppRecentFiles.java
new file mode 100644 (file)
index 0000000..c2b7b31
--- /dev/null
@@ -0,0 +1,93 @@
+package ie.dcu.apps.ist;
+
+import ie.dcu.apps.ist.recent.*;
+
+import java.io.*;
+
+/**
+ * Manages applications recent files list.
+ * 
+ * @author Kevin McGuinness
+ */
+public class AppRecentFiles extends RecentFiles {
+       public static final String APP_SETTINGS_PATH = ".ist";
+       public static final String HISTORY_FILE_NAME = ".history";
+
+       private static AppRecentFiles history;
+       
+       
+       private AppRecentFiles(File store) {
+               super(store);
+       }
+       
+       
+       public static AppRecentFiles getInstance() {
+               if (history == null) {
+                       history = create();
+               }
+               return history;
+       }
+       
+       
+       private static AppRecentFiles create() {
+               AppRecentFiles history = null;
+               try {
+                       history = new AppRecentFiles(getHistoryFile());
+                       history.load();
+               } catch (IOException e) {
+                       getLogger().warning("Unable to create history file: " + e);
+               }
+               
+               return history;
+       }
+       
+       
+       @Override
+       public void load() {
+               try {
+                       super.load();
+               } catch (IOException e) {
+                       getLogger().warning("Error loading recent documents list: " + e);
+               }
+       }
+
+       @Override
+       public void store() {
+               try {
+                       super.store();
+               } catch (IOException e) {
+                       getLogger().warning("Error storing recent documents list: " + e);
+               }
+       }
+
+
+       private static File getHistoryFile() throws IOException {
+               File file = new File(getSettingsDirectory(), HISTORY_FILE_NAME);
+               if (file.exists()) {
+                       // Check we can write
+                       if (file.canWrite()) {
+                               return file;
+                       }
+               } else {
+                       return file;
+               }
+               
+               throw new IOException("History file is unwritable");
+       }
+
+
+       private static File getSettingsDirectory() throws IOException {
+               String home = System.getProperty("user.home");
+               File settings = new File(home, APP_SETTINGS_PATH);
+               
+               if (!settings.exists()) {
+                       if (settings.mkdirs()) {
+                               return settings;
+                       }
+               } else {
+                       return settings;
+               }
+               
+               throw new IOException("Unable to create application settings directory");
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/AppRecentMenu.java b/image_annotation/src/ie/dcu/apps/ist/AppRecentMenu.java
new file mode 100644 (file)
index 0000000..84fe0cb
--- /dev/null
@@ -0,0 +1,113 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist;
+
+import ie.dcu.apps.ist.actions.ActionManager;
+import ie.dcu.apps.ist.actions.HoverMenuManager;
+import ie.dcu.apps.ist.actions.OpenAction;
+import ie.dcu.apps.ist.actions.OpenRecentAction;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Properties;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+
+/**
+ * Recent files menu.
+ * 
+ * @author Kevin McGuinness
+ */
+class AppRecentMenu extends HoverMenuManager {
+       private final AppRecentFiles history;
+       private final EmptyAction empty;
+       private final AppWindow window;
+       private IAction action;
+       
+       public AppRecentMenu(AppWindow window, IMenuManager parent) {
+               super("Open &Recent");
+               
+               this.window = window;
+               setParent(parent);
+               history = AppRecentFiles.getInstance();
+               add(empty = new EmptyAction());
+               addMenuListener(menuListener);
+       
+               ActionManager actions = window.getActions();
+               if (actions != null) {
+                       OpenAction openAction = actions.get(OpenAction.class);
+                       openAction.addPropertyChangeListener(actionListener);
+                       action = openAction;
+               }
+               
+               try {
+                       Properties props = window.getProperties();
+                       String icon = props.getProperty("AppRecentMenu.icon", 
+                               "file:icons/open-recent.png");
+                       setImageURL(new URL(icon));
+               } catch (MalformedURLException e) {
+                       // Ignore
+               }
+       }       
+       
+       @Override
+       public void fill(Menu parent, int index) {
+               super.fill(parent, index);
+               MenuItem item = getMenuItem();
+               if (item != null) {
+                       item.setEnabled(action.isEnabled());
+               }
+       }
+
+
+       private void buildMenu() {
+               removeAll();
+               
+               if (history.empty()) {
+                       add(empty);
+               } else {
+                       for (File file : history) {
+                               add(new OpenRecentAction(window.getActions(), file));
+                       }
+               }
+               
+               update(false);
+       }
+       
+       
+       private final class EmptyAction extends Action {
+               public EmptyAction() {
+                       setText("No Recent Files");
+                       setEnabled(false);
+               }
+       };
+       
+       
+       private final IMenuListener menuListener = new IMenuListener() {
+               public void menuAboutToShow(IMenuManager manager) {
+                       buildMenu();
+               }
+       };
+
+       
+       private final IPropertyChangeListener actionListener 
+               = new IPropertyChangeListener() {
+
+               public void propertyChange(PropertyChangeEvent event) {
+                       MenuItem item = getMenuItem();
+                       if (item != null) {
+                               item.setEnabled(action.isEnabled());
+                       }
+               }
+       };
+       
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/AppStatus.java b/image_annotation/src/ie/dcu/apps/ist/AppStatus.java
new file mode 100644 (file)
index 0000000..b888e21
--- /dev/null
@@ -0,0 +1,46 @@
+package ie.dcu.apps.ist;
+
+import java.net.*;
+
+import org.eclipse.jface.resource.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * Application status bar message type.
+ * 
+ * @author Kevin McGuinness
+ */
+public enum AppStatus {
+       Information, Warning, Error;
+       
+       public Image getIcon() {
+               String key = key();
+               Image image = JFaceResources.getImage(key);
+               if (image == null) {
+                       ImageRegistry registry = JFaceResources.getImageRegistry();
+                       ImageDescriptor descriptor = createImageDescriptor();
+                       registry.put(key, descriptor);
+                       image = registry.get(key);
+               }
+               return image;
+       }
+       
+       private ImageDescriptor createImageDescriptor() {
+               try {
+                       return ImageDescriptor.createFromURL(new URL(key()));
+               } catch (MalformedURLException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+       
+       private String key() {
+               switch (this) {
+               case Information:
+                       return "file:resources/icons/dialog-information.png";
+               case Warning:
+                       return "file:resources/icons/dialog-warning.png";
+               default:
+                       return "file:resources/icons/dialog-error.png";
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/AppWindow.java b/image_annotation/src/ie/dcu/apps/ist/AppWindow.java
new file mode 100644 (file)
index 0000000..a047dbe
--- /dev/null
@@ -0,0 +1,725 @@
+package ie.dcu.apps.ist;
+
+import ie.dcu.apps.ist.actions.*;
+import ie.dcu.apps.ist.event.*;
+import ie.dcu.apps.ist.exp.Experiment;
+import ie.dcu.apps.ist.views.*;
+import ie.dcu.segment.*;
+import ie.dcu.segment.annotate.*;
+import ie.dcu.swt.*;
+import ie.dcu.swt.event.*;
+import ie.dcu.swt.layout.LayoutFactory;
+import ie.dcu.util.*;
+
+import java.io.*;
+import java.net.*;
+import java.util.Properties;
+import java.util.logging.*;
+
+import org.eclipse.jface.action.*;
+import org.eclipse.jface.resource.*;
+import org.eclipse.jface.window.ApplicationWindow;
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Main interactive segmentation tool application window.
+ * 
+ * @author Kevin McGuinness
+ */
+public class AppWindow extends ApplicationWindow implements FileDropListener {
+       private static final Logger log = Logger.getLogger("AppWindow");
+
+       private final Properties props;
+
+       private AppPrefsManager prefsManager;
+       private ActionManager actions;
+       private Composite content;
+       private SegmentationView view;
+       private Shell shell;
+       private ImageObserver observer;
+       private Experiment experiment;
+       private ExperimentPanel experimentPanel;
+       private boolean experimentModeEmbedded;
+
+
+       public AppWindow() {
+               super(null);
+
+               props = loadProperties();
+
+               addMenuBar();
+               addStatusLine();
+       }
+       
+       
+       @Override
+       protected boolean canHandleShellCloseEvent() {
+               if (!ExitAction.confirmExit(this)) {
+                       return false; 
+               }
+               return super.canHandleShellCloseEvent();
+       }
+
+
+       private Properties loadProperties() {
+               try {
+                       return Application.loadProperties(getPropertiesFile());
+               } catch (IOException e) {
+                       log.severe("Unable to load properties file " + e.getMessage());
+                       throw new RuntimeException(e);
+               }
+       }
+       
+       private String getPropertiesFile() {
+               return OsUtils.isMacOS() ? "application.mac" : "application";
+       }
+
+
+       public void updateWindowTitle() {
+               String title;
+               if (hasContext()) {
+                       String file = getContext().getFile().getName();
+                       title = String.format("%s [%s]", Application.APP_NAME, file);
+                       
+               } else {
+                       title = Application.APP_NAME;
+               }
+               
+               if (isExperimentMode()) {
+                       title += " - Experiment Mode";
+               }
+               
+               getShell().setText(title);
+       }
+
+
+       private SegmentationView createView(Composite parent) {
+
+               // Load props
+               Properties props;
+               try {
+                       props = Application.loadProperties("view"); 
+               } catch (IOException e) {
+                       log.severe("Error loading view properties " + e.getLocalizedMessage());
+                       throw new RuntimeException(e);
+               }
+
+               // Create view
+               SegmentationView view = new SegmentationView(props, parent, 0);
+
+               boolean blocksOnFork = false;
+               
+               // Set runnable context 
+               view.setRunnableContext(this, blocksOnFork);
+
+               // Add observer
+               observer = new ImageObserver(view);
+
+               // Return new view
+               return view;
+       }
+
+
+       private static ImageDescriptor createImageDescriptor(String url) {
+               try {
+                       return ImageDescriptor.createFromURL(new URL(url));
+               } catch (MalformedURLException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+
+       private void updateEnabledActions() {
+               ActionManager a = getActions();
+               boolean ctxAvailable = hasContext();
+               boolean experimentMode = isExperimentMode();
+               
+               a.setEnabled(OpenAction.class, !experimentMode);
+               a.setEnabled(PreferencesAction.class, !experimentMode);
+               a.setEnabled(SaveAction.class, ctxAvailable && !experimentMode);
+               a.setEnabled(SaveAsAction.class, ctxAvailable && !experimentMode);
+               a.setEnabled(ExportViewAction.class, ctxAvailable && !experimentMode);
+               a.setEnabled(ExportTransparentPNGAction.class, ctxAvailable && !experimentMode);
+               a.setEnabled(PrintAction.class, ctxAvailable && !experimentMode);
+               a.setEnabled(CopyAction.class, ctxAvailable && !experimentMode);
+               a.setEnabled(UndoAction.class, ctxAvailable && view.canUndo());
+               a.setEnabled(RedoAction.class, ctxAvailable && view.canRedo());
+               a.setEnabled(NextAction.class, ctxAvailable && !experimentMode);
+               a.setEnabled(PreviousAction.class, ctxAvailable && !experimentMode);
+               a.setEnabled(OpenExperimentAction.class, !experimentMode);
+               
+               updateExportImageMapAction();
+               
+               if (experimentMode) {
+                       
+                       boolean changeSelection = false;
+                       
+                       // Enable experiment segmenters
+                       for (SelectSegmenterAction s : a.getSegmentationActions()) {
+                               Segmenter segmenter = s.getSegmenter();
+                               boolean enabled = experiment.using(segmenter);
+                               s.setEnabled(enabled);
+                               
+                               if (!s.isEnabled() && s.isChecked()) {
+                                       // The selected segmenter has been disabled,
+                                       // we need to select a different one
+                                       changeSelection = true;
+                                       s.setChecked(false);
+                               }
+                       }
+                       
+                       if (changeSelection) {
+                               // Select the first available segmenter
+                               for (SelectSegmenterAction s : a.getSegmentationActions()) {
+                                       if (experiment.using(s.getSegmenter())) {
+                                               s.setChecked(true);
+                                               s.run();
+                                               break;
+                                       }
+                               }
+                       }
+                       
+               } else {
+                       // Enable all select segmenter actions
+                       for (SelectSegmenterAction s : a.getSegmentationActions()) {
+                               s.setEnabled(true);
+                       }
+               }
+       }
+       
+       private void updateExportImageMapAction() {
+               ActionManager a = getActions();
+               SegmentationContext ctx = getContext();
+               
+               if (ctx != null && !isExperimentMode()) {
+                       AnnotationManager am = ctx.getAnnotations();
+                       boolean hasObject = am.hasForegroundAnnotation() 
+                               && am.hasBackgroundAnnotation();
+                       a.setEnabled(ExportImageMapAction.class, hasObject);
+               
+               } else {
+                       a.setEnabled(ExportImageMapAction.class, false);
+               }
+       }
+       
+       
+       private void updateUndoRedoActions() {
+               ActionManager a = getActions();
+               boolean ctxAvailable = hasContext();
+               a.setEnabled(UndoAction.class, ctxAvailable && view.canUndo());
+               a.setEnabled(RedoAction.class, ctxAvailable && view.canRedo());
+       }
+
+
+       @Override
+       protected void configureShell(Shell shell) {
+               this.shell = shell;
+               super.configureShell(shell);
+               updateWindowTitle();
+               loadIcons(shell);
+               shell.setSize(800, 600);
+               SwtUtils.center(shell);
+       }
+       
+       
+       private void loadIcons(Shell shell) {
+               final String[] icons = { 
+                               "resources/icons/icon-16.png",
+                               "resources/icons/icon-24.png",
+                               "resources/icons/icon-32.png",
+                               "resources/icons/icon-48.png"
+               };
+               
+               Image[] images = new Image[icons.length];
+               Display display = shell.getDisplay();
+               
+               try {
+                       int i = 0;
+                       for (String file : icons) {
+                               images[i++] = new Image(display, file);
+                       }
+                       
+                       shell.setImages(images);
+       
+               } catch (SWTException e) {
+                       log.warning("Error loading application window icons: " 
+                               + e.getLocalizedMessage());
+               }
+       }
+
+
+       @Override
+       protected Control createContents(Composite parent) {
+               content = new Composite(parent, SWT.NONE);
+
+               content.setLayout(LayoutFactory.createGridLayout(0, 0, 2, false));
+
+               view = createView(content);
+               view.setLayoutData(LayoutFactory.createGridData());
+               view.addContextChangeListener(contextListener);
+               
+               SwtUtils.createFileDropTarget(view, this);
+
+               // Done creating contents
+               getPrefsManager().update();
+               updateEnabledActions();
+
+               return content;
+       }
+
+
+       @Override
+       protected boolean showTopSeperator() {
+               return false;
+       }
+
+
+       @Override
+       protected MenuManager createMenuManager() {
+               MenuManager bar = new MenuManager();
+
+               ActionManager actions = getActions();
+
+               MenuManager file = addMenu(bar, "&File");
+               file.add(actions.get(OpenAction.class));
+               
+               file.add(new AppRecentMenu(this, file));
+               
+               file.add(new Separator());
+               file.add(actions.get(SaveAction.class));
+               file.add(actions.get(SaveAsAction.class));
+               file.add(new Separator());
+               
+               // Export menu ->
+               MenuManager exportMenu = addMenu(file, "&Export", 
+                       props.getProperty("ExportMenu.icon"));
+               
+               exportMenu.add(actions.get(ExportViewAction.class));
+               exportMenu.add(actions.get(ExportImageMapAction.class));
+               exportMenu.add(actions.get(ExportTransparentPNGAction.class));
+               
+               file.add(new Separator());
+               file.add(actions.get(PrintAction.class));
+               file.add(new Separator());
+               file.add(actions.get(ExitAction.class));
+
+               MenuManager edit = addMenu(bar, "&Edit");
+
+               edit.add(actions.get(UndoAction.class));
+               edit.add(actions.get(RedoAction.class));
+               edit.add(new Separator());
+               edit.add(actions.get(CopyAction.class));
+               edit.add(new Separator());
+               edit.add(actions.get(PreferencesAction.class));
+
+               MenuManager tools = addMenu(bar, "&Tools");
+               tools.add(actions.get(OpenExperimentAction.class));
+               tools.add(new Separator());
+               
+               for (SelectSegmenterAction a : actions.getSegmentationActions()) {
+                       tools.add(a);
+               }
+               
+               tools.add(new Separator());
+               tools.add(actions.get(ConfigureSegmenterAction.class));
+               
+               MenuManager go = addMenu(bar, "&Go");
+               go.add(actions.get(NextAction.class));
+               go.add(actions.get(PreviousAction.class));
+               
+               
+               MenuManager help = addMenu(bar, "&Help");
+
+               help.add(actions.get(HelpAction.class));
+               help.add(actions.get(AboutAction.class));
+                               
+               if (OsUtils.isMacOSX()) {
+                       // Enhance the UI on the Mac
+                       IAction aboutAction = actions.get(AboutAction.class);
+                       IAction prefAction = actions.get(PreferencesAction.class);
+                       Listener quitListener = new Listener() {
+                               public void handleEvent(Event evt) {
+                                       getActions().get(ExitAction.class).runWithEvent(evt);
+                               }
+                       };
+                       CocoaUIEnhancer enhancer = new CocoaUIEnhancer(Application.APP_NAME);
+                       enhancer.hookApplicationMenu(Display.getDefault(), 
+                               quitListener, aboutAction, prefAction);
+               }
+
+               return bar;
+       }
+
+
+       protected static MenuManager addMenu(MenuManager parent, String text) {
+               MenuManager menu = new HoverMenuManager(text);
+               parent.add(menu);
+               return menu;
+       }
+       
+       protected static MenuManager addMenu(MenuManager parent, 
+                       String text, String image) {
+               
+               MenuManager menu;
+               try {
+                       menu = new HoverMenuManager(text, image != null ? 
+                               new URL(image) : null);
+               } catch (MalformedURLException e) {
+                       log.log(Level.WARNING, "Malformed URL", e);
+                       menu = new HoverMenuManager(text);
+               }
+               
+               parent.add(menu);
+               return menu;
+       }
+       
+       
+       
+       public void setExperiment(Experiment ex) {
+               if (experiment != ex) {
+                       experiment = ex;
+                       setContext(null);
+                       
+                       if (ex == null) {
+                               
+                               if (experimentPanel != null) {
+                                       experimentPanel.dispose();
+                                       experimentPanel = null;
+                                       content.layout();
+                               }
+                       } else {
+                       
+                               if (experimentModeEmbedded) {
+                                       experimentPanel = new ExperimentPanel(this, content, SWT.NONE);
+                                       GridData data = new GridData(SWT.FILL, SWT.FILL, false, true);
+                                       data.widthHint = 180;
+                                       data.verticalIndent = 5;
+                                       experimentPanel.setLayoutData(data);
+                                       content.layout();
+                                       
+                               } else {
+                                       ExperimentPanel.open(this);
+                               }
+                       }
+                       updateEnabledActions();
+                       updateWindowTitle();
+               }
+       }
+       
+       
+       public Experiment getExperiment() {
+               return experiment;
+       }
+
+
+       public boolean isExperimentMode() {
+               return experiment != null;
+       }
+
+
+       public void setExperimentModeEmbedded(boolean on) {
+               this.experimentModeEmbedded = on;
+       }
+
+
+       public AppPrefs getPrefs() {
+               return getPrefsManager().getPrefs();
+       }
+
+
+       AppPrefsManager getPrefsManager() {
+               if (prefsManager == null) {
+                       prefsManager = new AppPrefsManager(this);
+               }
+               return prefsManager;
+       }
+
+
+       public Properties getProperties() {
+               return props;
+       }
+
+
+       public ActionManager getActions() {
+               if (actions == null) {
+                       actions = new ActionManager(this);
+               }
+               return actions;
+       }
+
+
+       public Shell getShell() {
+               Shell shell = super.getShell();
+               if (shell == null) {
+                       return this.shell;
+               }
+               return shell;
+       }
+
+
+       public SegmentationView getView() {
+               return view;
+       }
+
+
+       public SegmentationContext getContext() {
+               if (view != null) {
+                       return view.getContext();
+               }
+               return null;
+       }
+
+
+       public File getContextFile() {
+               if (hasContextFile()) {
+                       return getContext().getFile();
+               }
+               return null;
+       }
+
+
+       public Image getIcon(String url) {
+               Image image = JFaceResources.getImage(url);
+               if (image == null) {
+                       ImageRegistry registry = JFaceResources.getImageRegistry();
+                       ImageDescriptor descriptor = createImageDescriptor(url);
+                       registry.put(url, descriptor);
+                       image = registry.get(url);
+               }
+               return image;
+       }
+
+
+       public boolean hasContext() {
+               if (view != null) {
+                       return view.getContext() != null;
+               }
+               return false;
+       }
+
+
+       public boolean hasContextFile() {
+               return getContext() != null ? getContext().hasContextFile() : false;
+       }
+
+
+       public void setEnableFeedback(boolean on) {
+               if (observer != null) {
+                       observer.setEnabled(on);
+               }
+       }
+
+
+       public void setContext(SegmentationContext ctx) {
+               if (ctx != null) {
+                       // Set a segmenter if one has not been set
+                       if (!view.hasSegmenter()) {
+                               SegmenterRegistry registry = SegmenterRegistry.getInstance();
+                               view.setSegmenter(registry.getDefault());
+                       }
+               }
+       
+               // Set context
+               view.setContext(ctx);
+               updateWindowTitle();
+       }
+
+
+       public void status(String message) {
+               setStatus(message);
+       }
+
+
+       public void status(String format, Object... args) {
+               setStatus(String.format(format, args));
+       }
+
+
+       public void status(Image image, String format, Object... args) {
+               StatusLineManager manager = getStatusLineManager();
+               if (manager != null) {
+                       manager.setMessage(image, String.format(format, args));
+               }
+       }
+
+
+       public void status(AppStatus s, String format, Object... args) {
+               if (format == null) {
+                       setStatus(null);
+
+               } else {
+                       StatusLineManager manager = getStatusLineManager();
+                       if (manager != null) {
+                               if (s == AppStatus.Error) {
+                                       manager.setErrorMessage(s.getIcon(), String.format(format, args));
+                               } else {
+                                       manager.setMessage(s.getIcon(), String.format(format, args));
+                               }
+                       }
+               }
+       }
+
+
+       public void drop(FileDropEvent evt) {
+               System.out.println("drop received");
+               for (File f : evt.files()) {
+                       if (isAcceptable(f)) {
+                               getActions().get(OpenAction.class).open(f);
+                               break;
+                       }
+               }
+       }
+
+
+       public boolean isAcceptable(File file) {
+               String ext = FileUtils.getExtension(file);
+               return (ext.equals(".ctx") || SwtUtils.getImageFormat(file) != -1);
+       }
+
+       
+       private void handleContextChanged(ContextChangedEvent evt) {
+               
+               // Remove listener from old context
+               if (evt.oldContext != null) {
+                       evt.oldContext.removeAnnotationListener(annotationListener);
+               }
+               
+               // Add listener to new context
+               if (evt.newContext != null) {
+                       evt.newContext.addAnnotationListener(annotationListener);
+               }
+               
+               // Update application state
+               updateEnabledActions();
+       }
+       
+       
+       private void handleAnnotationPerformed(AnnotationEvent e) {
+               
+               // Update state of undo and redo menu items
+               updateUndoRedoActions();
+               updateExportImageMapAction();
+       }
+       
+       
+       private final ContextChangeListener contextListener = new ContextChangeListener() {
+               public void contextChanged(ContextChangedEvent evt) {
+                       handleContextChanged(evt);
+               }
+       };
+       
+       
+       private final AnnotationListener annotationListener = new AnnotationAdapter() {
+               public void annotationsChanged(AnnotationEvent e) {
+                       handleAnnotationPerformed(e);
+               }               
+       };
+       
+       
+       private class ImageObserver implements MouseMoveListener, ContextChangeListener {
+               private static final String MONOSPACE_FONT = "Monospace";
+
+               private final ImageControl ctrl;
+               private ImageData image;
+               private boolean inside;
+               private boolean enabled;
+
+
+               public ImageObserver(SegmentationView view) {
+                       view.addContextChangeListener(this);
+                       view.getCanvas().addMouseMoveListener(this);
+                       ctrl = view.getImageControl();
+                       contextChanged(view.getContext());
+                       FontDescriptor fd = FontDescriptor.createFrom(MONOSPACE_FONT, 8, SWT.NORMAL);
+                       JFaceResources.getFontRegistry().put(MONOSPACE_FONT, fd.getFontData());
+               }
+
+
+               public void setEnabled(boolean enabled) {
+                       if (this.enabled != enabled) {
+                               status(null);
+                               Font font = JFaceResources.getDefaultFont();
+                               getStatusLineManager().getControl().setFont(font);
+                               this.inside = false;
+                               this.enabled = enabled;
+                       }
+               }
+
+
+               public boolean isEnabled() {
+                       return enabled;
+               }
+
+
+               public void mouseMove(MouseEvent e) {
+                       if (isEnabled()) {
+                               Point pt = getImagePoint(e);
+                               if (pt != null) {
+                                       inside(pt, getColor(pt));
+                               } else {
+                                       outside();
+                               }
+                       }
+               }
+
+
+               private void outside() {
+                       if (inside) {
+                               status(null);
+                               Font font = JFaceResources.getDefaultFont();
+                               getStatusLineManager().getControl().setFont(font);
+                               inside = false;
+                       }
+               }
+
+
+               private final Point getImagePoint(MouseEvent e) {
+                       if (image != null) {
+                               Point pt = new Point(e.x, e.y);
+                               if (ctrl.imageContains(pt)) {
+                                       return ctrl.canvasToImage(pt);
+                               }
+                       }
+                       return null;
+               }
+
+
+               private final RGB getColor(Point pt) {
+                               
+                       int pixel = image.getPixel(pt.x, pt.y);
+                       return image.palette.getRGB(pixel);
+               }
+
+
+               private void inside(Point pt, RGB c) {
+                       if (!inside) {
+                               Font font = JFaceResources.getFont(MONOSPACE_FONT);
+                               getStatusLineManager().getControl().setFont(font);
+                       }
+
+                       status(AppStatus.Information, 
+                                       "Location [%4d,%4d] Color [%3d,%3d,%3d]",
+                                       pt.x, pt.y, c.red, c.green, c.blue);
+                       
+                       inside = true;
+               }
+
+
+               public void contextChanged(ContextChangedEvent evt) {
+                       contextChanged(evt.newContext);
+               }
+
+
+               public void contextChanged(SegmentationContext ctx) {
+                       if (ctx != null) {
+                               image = ctx.getImageData();
+                       } else {
+                               image = null;
+                       }
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/Application.java b/image_annotation/src/ie/dcu/apps/ist/Application.java
new file mode 100644 (file)
index 0000000..bbd3b38
--- /dev/null
@@ -0,0 +1,110 @@
+package ie.dcu.apps.ist;
+
+import ie.dcu.util.*;
+
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.util.*;
+
+import static ie.dcu.util.FileUtils.pathJoin;
+import static ie.dcu.util.OsUtils.*;
+
+/**
+ * Base application. Contains information strings and methods to load
+ * application wide resources.
+ * 
+ * @author Kevin McGuinness
+ */
+public class Application {
+       public static final String APP_ID   = "ist";
+       public static final String APP_NAME = "Interactive Segmentation and Annotation Tool";
+       public static final String APP_VERSION  = "1.3.4";
+       public static final String APP_RESOURCE_DIR = "resources";
+       
+       /**
+        * Default locations to look for plugins
+        */
+       public static final String[] DEFAULT_PLUGIN_SEARCH_PATH 
+               = defaultPluginSearchPath();
+       
+       /**
+        * Loads a properties file from the application resource area
+        * (resources/config)
+        * 
+        * @param name
+        *        The properties file name. ".properties" will be appended if
+        *        necessary.
+        * @return A Properties object
+        * @throws IOException
+        *         If there is an error creating the Properties object.
+        */
+       public static Properties loadProperties(String name) throws IOException {
+               if (!name.endsWith(".properties")) {
+                       name = name + ".properties";
+               }
+               
+               String path = FileUtils.pathJoin(APP_RESOURCE_DIR, "config", name);
+               File file = new File(path);
+               System.out.println("Path:" + file);
+               return PropsUtils.load(file);
+       }
+       
+       /**
+        * Returns the users plugins folder
+        */
+       public static String userPluginsFolder() {
+               return pathJoin(userHome(), ".ist", "plugins");
+       }
+       
+       /**
+        * Returns the applications base folder
+        */
+       public static String applicationFolder() {
+               String apphome = System.getenv("IST_HOME");
+               if (apphome != null) {
+                       File file = new File(apphome);
+                       if  (file.isDirectory()) {
+                               return file.getAbsolutePath();
+                       }
+               } 
+               
+               ProtectionDomain domain = Application.class.getProtectionDomain();
+               CodeSource source = domain.getCodeSource();
+               URL location = source.getLocation();
+               String path = location.getPath();
+               try {
+                       
+                       path = URLDecoder.decode(path, "UTF-8");
+                       if (isWindows()) {
+                               path = path.substring(1);
+                       }
+                               
+                       path = new File(path).getParent();
+               } catch (UnsupportedEncodingException e) {
+                       path = System.getProperty("user.dir");
+               }
+                       
+               return path;
+       }
+       
+       public static String applicationPluginsFolder() {
+               return pathJoin(applicationFolder(), "plugins");
+       }
+       
+       public static String osxPluginSearchPath() {
+               return pathJoin(userHome(), "Library", 
+                       "Application Support", APP_NAME, "Plugins");
+       }
+       
+       private static String[] defaultPluginSearchPath() {
+               ArrayList<String> paths = new ArrayList<String>();
+               paths.add(userPluginsFolder());
+               if (isMacOSX()) {
+                       paths.add(osxPluginSearchPath());
+               }
+               paths.add(applicationPluginsFolder());
+               return paths.toArray(new String[paths.size()]);
+       }
+       
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/EvaluatorRegistry.java b/image_annotation/src/ie/dcu/apps/ist/EvaluatorRegistry.java
new file mode 100644 (file)
index 0000000..d7bc7b4
--- /dev/null
@@ -0,0 +1,70 @@
+package ie.dcu.apps.ist;
+
+import ie.dcu.eval.*;
+
+import java.util.*;
+
+public class EvaluatorRegistry {
+       private static EvaluatorRegistry instance;
+       private final Set<Evaluator> evaluators;
+       
+       private EvaluatorRegistry() {
+               evaluators = new LinkedHashSet<Evaluator>();
+               init();
+       }
+       
+       
+       private void init() {
+               add(new ConfusionMatrixEvaluator());
+               add(new BoundaryAccuracyEvaluator());
+       }
+       
+       
+       public static EvaluatorRegistry getInstance() {
+               if (instance == null) {
+                       instance = new EvaluatorRegistry();
+               }
+               return instance;
+       }
+       
+       
+       public Evaluator find(String name) {
+               for (Evaluator e : evaluators) {
+                       
+                       // Check name
+                       String ename = e.getName();
+                       if (ename.equals(name)) {
+                               return e;
+                       }
+                       
+                       // Check class name
+                       String cname = e.getClass().getName();
+                       if (cname.equals(name)) {
+                               return e;
+                       }
+                       
+                       // Check simple name
+                       String sname = e.getClass().getSimpleName();
+                       if (sname.equals(name)) {
+                               return e;
+                       }
+               }
+               
+               return null;
+       }
+       
+       
+       public void add(Evaluator evaluator) {
+               evaluators.add(evaluator);
+       }
+       
+       
+       public Set<Evaluator> evaluators() {
+               return Collections.unmodifiableSet(evaluators);
+       }
+
+
+       public Iterator<Evaluator> iterator() {
+               return evaluators.iterator();
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/Main.java b/image_annotation/src/ie/dcu/apps/ist/Main.java
new file mode 100644 (file)
index 0000000..d878efd
--- /dev/null
@@ -0,0 +1,119 @@
+package ie.dcu.apps.ist;
+
+import ie.dcu.plugin.*;
+import ie.dcu.segment.Segmenter;
+
+import java.util.logging.Logger;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Application launcher.
+ * 
+ * @author Kevin McGuinness
+ */
+public class Main {
+       public static final Logger log = Logger.getLogger("Main");
+       
+       /**
+        * Message to show when GDI+ is not installed.
+        */
+       private static final String NO_GDIPLUS = 
+               "Unable to load required library: GDI+ (gdiplus.dll)\n\n" +
+               "The GDI+ library needs to be installed before this program " +
+               "can be used on this platform. See the note at the end of " +
+               "the download page for further details.";
+               
+       
+       public static void main(String[] args) {
+               System.out.print(Application.DEFAULT_PLUGIN_SEARCH_PATH);
+               for (String s: Application.DEFAULT_PLUGIN_SEARCH_PATH) {
+                       System.out.println(s);
+               }
+
+               Display.setAppName(Application.APP_NAME);
+               check();
+               loadPlugins();
+               AppWindow window = new AppWindow();
+               window.setBlockOnOpen(true);
+               window.open();
+               System.exit(0);
+       }
+       
+       private static void loadPlugins() {
+               PluginManager manager = new PluginManager();
+               for (String path : Application.DEFAULT_PLUGIN_SEARCH_PATH) {
+                       manager.searchPath().add(path);
+               }
+               manager.loadPlugins();
+               for (Plugin plugin : manager.plugins()) {
+                       String classname = plugin.getMetadata("segmenter");
+                       if (classname != null) {
+                               loadSegmenterPlugin(plugin, classname);
+                       }
+               }
+       }
+
+       private static void loadSegmenterPlugin(Plugin plugin, String classname) {
+               try {
+                       Segmenter segmenter = (Segmenter) 
+                               plugin.loadObject(classname);
+                       
+                       SegmenterRegistry.getInstance().add(segmenter);
+                       
+               } catch (PluginException e) {
+                       log.severe("Unable to load plugin: " + e);
+               }
+       }
+
+       public static boolean contains(String[] args, String argument) {
+               for (String arg : args) {
+                       while (arg.startsWith("-")) {
+                               arg = arg.substring(1);
+                       }
+                       
+                       if (arg.equals(argument)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
+       private static void check() {
+               // Check for potential missing GDI+ on Win2K, NT, ME 98
+               String os = System.getProperty("os.name");
+               if (os.equals("Windows 2000") ||
+                       os.equals("Windows NT") ||
+                       os.equals("Windows ME") ||
+                       os.equals("Windows 98")) 
+               {
+                       try {
+                               System.loadLibrary("gdiplus");
+                       } catch (RuntimeException e) {
+                               exit(NO_GDIPLUS);
+                       }
+               }
+       }
+       
+       static void exit(String message) {
+               Display display = Display.getDefault();
+               Rectangle rect = display.getBounds();
+               
+               Shell shell = display.getActiveShell();
+               if (shell == null) {
+                       shell = new Shell(display, SWT.NO_TRIM);
+                       shell.setBounds(rect.width/2, rect.height/2, 0, 0);
+                       shell.open();
+                       shell.setText("Error");
+               }
+               
+               MessageBox box = new MessageBox(shell, SWT.ICON_ERROR);
+               box.setText("Error");
+               box.setMessage(message);
+               box.open();
+               display.dispose();
+               System.exit(1);
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/PainterRegistry.java b/image_annotation/src/ie/dcu/apps/ist/PainterRegistry.java
new file mode 100644 (file)
index 0000000..7b437b0
--- /dev/null
@@ -0,0 +1,46 @@
+package ie.dcu.apps.ist;
+
+import ie.dcu.segment.painters.*;
+
+import java.util.*;
+
+public class PainterRegistry {
+       private final LinkedHashMap<String, SegmentationPainter> painters;
+
+       public PainterRegistry() {
+               painters = new LinkedHashMap<String, SegmentationPainter>();
+               init();
+       }
+       
+       
+       private void init() {
+               add(new CombinedPainter());
+               add(new OriginalPainter());
+               add(new MarkupPainter());
+               add(new MaskPainter());
+               add(new ForegroundOnlyPainter());
+               add(new OutlineOverlayPainter());
+       }
+       
+       
+       public void add(SegmentationPainter painter) {
+               painters.put(painter.getName(), painter);
+       }
+       
+       
+       public SegmentationPainter get(String painter) {
+               return painters.get(painter);
+       }
+       
+       
+       public Collection<SegmentationPainter> values() {
+               return painters.values();
+       }
+       
+       
+       public void dispose() {
+               for (SegmentationPainter p : values()) {
+                       p.dispose();
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/SegmenterRegistry.java b/image_annotation/src/ie/dcu/apps/ist/SegmenterRegistry.java
new file mode 100644 (file)
index 0000000..f3fec09
--- /dev/null
@@ -0,0 +1,107 @@
+package ie.dcu.apps.ist;
+
+import ie.dcu.segment.*;
+
+import java.util.*;
+
+/**
+ * Registry for segmenters.
+ * 
+ * @author Kevin McGuinness
+ */
+public class SegmenterRegistry implements Iterable<Segmenter> {
+       private static final String DEFAULT_SEGMENTER_NAME = "IgcSegmenter";
+       private static SegmenterRegistry instance;
+       private final Set<Segmenter> segmenters;
+       
+       private SegmenterRegistry() {
+               segmenters = new LinkedHashSet<Segmenter>();
+               init();
+       }
+       
+       
+       private void init() {
+               // OutlineSegmenter is not very useful
+               // add(new OutlineSegmenter());
+               
+               // Geodesic Active Contours is too sensitive to parameters
+               // for general use on natural images.
+               // add(new SeededGacSegmenter());
+               
+               //add(new SrgSegmenter());
+               //add(new IgcSegmenter());
+               //add(new BptSegmenter());
+               //add(new SioxSegmenter());
+               //add(new SpatiogramSegmenter());
+       }
+
+
+       public static SegmenterRegistry getInstance() {
+               if (instance == null) {
+                       instance = new SegmenterRegistry();
+               }
+               return instance;
+       }
+       
+       
+       public Segmenter find(String name) {
+               for (Segmenter s : segmenters) {
+                       
+                       // Check name
+                       String ename = s.getName();
+                       if (ename.equals(name)) {
+                               return s;
+                       }
+                       
+                       // Check class name
+                       String cname = s.getClass().getName();
+                       if (cname.equals(name)) {
+                               return s;
+                       }
+                       
+                       // Check simple name
+                       String sname = s.getClass().getSimpleName();
+                       if (sname.equals(name)) {
+                               return s;
+                       }
+               }
+               
+               return null;
+       }
+       
+       
+       public boolean isDefault(Segmenter s) {
+               if (s != null) {
+                       if (segmenters.size() == 1 && segmenters.contains(s)) {
+                               return true;
+                       }
+                       return s.getClass().getSimpleName().equals(DEFAULT_SEGMENTER_NAME);
+               }
+               return false;
+       }
+       
+       
+       public Segmenter getDefault() {
+               for (Segmenter s : segmenters) {
+                       if (isDefault(s)) {
+                               return s;
+                       }
+               }
+               return null;
+       }
+       
+       
+       public void add(Segmenter segmenter) {
+               segmenters.add(segmenter);
+       }
+       
+       
+       public Set<Segmenter> segmenters() {
+               return Collections.unmodifiableSet(segmenters);
+       }
+
+
+       public Iterator<Segmenter> iterator() {
+               return segmenters.iterator();
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/AboutAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/AboutAction.java
new file mode 100644 (file)
index 0000000..be5d61f
--- /dev/null
@@ -0,0 +1,109 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.Application;
+import ie.dcu.swt.layout.LayoutFactory;
+
+import org.eclipse.jface.dialogs.*;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.*;
+
+
+/**
+ * Show an about dialog.
+ * 
+ * @author Kevin McGuinness
+ */
+public class AboutAction extends AppAction {
+       
+       private AboutBox dialog;
+       
+       public AboutAction(ActionManager m) {
+               super(m);
+       }
+
+       
+       @Override 
+       public void run() { 
+               if (dialog == null) {
+                       dialog = new AboutBox();
+               }
+               dialog.open();
+       }
+       
+       
+       private class AboutBox extends Dialog {
+               
+               private static final String MESSAGE = 
+                       "   Kevin McGuinness <a href=\"mailto:kevin.mcguinness@eeng.dcu.ie\">" +
+                       "kevin.mcguinness@eeng.dcu.ie</a>\n" +
+                       "   Center for Digital Video Processing\n" +
+                       "   Dublin City University.\n" +
+                       "   <a href=\"http://www.cdvp.dcu.ie\">http://www.cdvp.dcu.ie</a>";
+               
+               
+               private Composite composite;
+               
+
+               protected AboutBox() {
+                       super(window);
+               }
+               
+
+               @Override
+               protected Control createDialogArea(Composite parent) {
+                       composite = new Composite(parent, SWT.NONE);
+                       composite.setLayout(LayoutFactory.createGridLayout(5, 5));
+                       
+                       String image = string("aboutImage");
+                       addImage(image);
+                       addLabel(String.format("Version %s", Application.APP_VERSION), SWT.CENTER);
+                       addLabel(" SWT Version " + swtVersionString(), SWT.CENTER);
+                       addLabel(" Developed By:", SWT.LEFT);
+                       addLink(MESSAGE);
+               
+                       return composite;
+               }
+               
+               private String swtVersionString() {
+                       return String.format("%d (%s)", SWT.getVersion(), SWT.getPlatform());
+               }
+       
+               
+               @Override
+               protected void createButtonsForButtonBar(Composite parent) {
+                       createButton(parent, 
+                                       IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+               }
+
+
+               @Override
+               protected void configureShell(Shell shell) {
+                       super.configureShell(shell);
+                       shell.setText("About");
+               }
+               
+               
+               private void addLink(String string) {
+                       Link link = new Link(composite, 0);
+                       link.setText(string);
+                       link.setLayoutData(LayoutFactory.createGridData());
+               }
+
+               
+               private void addLabel(String text, int alignment) {
+                       Label label = new Label(composite, 0);
+                       label.setText(text);
+                       label.setAlignment(alignment);
+                       label.setLayoutData(LayoutFactory.createGridData());
+                       label.setFont(JFaceResources.getBannerFont());
+               }
+               
+               private void addImage(String url) {
+                       Label label = new Label(composite, 0);
+                       label.setImage(window.getIcon(url));
+                       label.setLayoutData(LayoutFactory.createGridData());
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/ActionManager.java b/image_annotation/src/ie/dcu/apps/ist/actions/ActionManager.java
new file mode 100644 (file)
index 0000000..b1897f8
--- /dev/null
@@ -0,0 +1,133 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.*;
+import ie.dcu.segment.Segmenter;
+import ie.dcu.util.OsUtils;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.logging.Logger;
+
+/**
+ * Manages application actions.
+ * 
+ * @author Kevin McGuinness
+ */
+public class ActionManager {
+       private static final Logger log = Logger.getLogger("ActionManager");
+       
+       private final AppWindow window;
+       private final Map<String, AppAction> actions;
+       private ArrayList<SelectSegmenterAction> segmenterActions;
+       private Properties props;
+       
+       
+       public ActionManager(AppWindow window) {
+               
+               this.window = window;
+               this.actions = new HashMap<String, AppAction>();
+               
+               try {
+                       this.props = Application.loadProperties(getPropertiesFile());
+               } catch (IOException e) {
+                       log.severe("Error loading action properties: " + 
+                                       e.getLocalizedMessage());
+                       throw new RuntimeException(e);
+               }
+               
+               init();
+       }
+       
+       
+       private String getPropertiesFile() {
+               return OsUtils.isMacOS() ? "actions.mac" : "actions";
+       }
+       
+       
+       Properties getProperties() {
+               return props;
+       }
+       
+       
+       AppWindow getWindow() {
+               return window;
+       }
+       
+
+       public void init() {
+               add(new OpenAction(this));
+               add(new SaveAction(this));
+               add(new SaveAsAction(this));
+               add(new AboutAction(this));
+               add(new CopyAction(this));
+               add(new ExitAction(this));
+               add(new ExportViewAction(this));
+               add(new ExportImageMapAction(this));
+               add(new ExportTransparentPNGAction(this));
+               add(new HelpAction(this));
+               add(new PreferencesAction(this));
+               add(new PrintAction(this));
+               add(new RedoAction(this));
+               add(new UndoAction(this));
+               add(new NextAction(this));
+               add(new PreviousAction(this));
+               add(new OpenExperimentAction(this));
+               add(new ConfigureSegmenterAction(this));
+               
+               // Add select segmenter actions
+               SegmenterRegistry registry = SegmenterRegistry.getInstance();
+               for (Segmenter s : registry) {
+                       add(new SelectSegmenterAction(this, registry, s));
+               }
+       }
+       
+       
+       public void add(AppAction action) {
+               actions.put(action.id(), action);
+       }
+       
+       
+       public <T extends AppAction> T get(Class<T> clazz) {
+               return clazz.cast(actions.get(id(clazz)));
+       } 
+       
+       
+       public <T extends AppAction> T get(Class<T> clazz, String id) {
+               return clazz.cast(actions.get(id));
+       }
+       
+       
+       public void setEnabled(String id, boolean enabled) {
+               AppAction action = actions.get(id);
+               if (action != null) {
+                       action.setEnabled(enabled);
+               }
+       }
+       
+       
+       public <T extends AppAction> void setEnabled(Class<T> clazz, boolean enabled) {
+               AppAction action = get(clazz);
+               if (action != null) {
+                       action.setEnabled(enabled);
+               }
+       }
+       
+       
+       public Collection<SelectSegmenterAction> getSegmentationActions() {
+               if (segmenterActions == null) {
+                       segmenterActions = new ArrayList<SelectSegmenterAction>();
+                       for (AppAction a : actions.values()) {
+                               if (a instanceof SelectSegmenterAction) {
+                                       segmenterActions.add((SelectSegmenterAction) a);
+                               }
+                       }
+               }
+               
+               return Collections.unmodifiableCollection(segmenterActions);
+       }
+       
+       
+       private String id(Class<?> clazz) {
+               return clazz.getName();
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/AppAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/AppAction.java
new file mode 100644 (file)
index 0000000..a5a11a8
--- /dev/null
@@ -0,0 +1,122 @@
+package ie.dcu.apps.ist.actions;
+
+import java.util.logging.*;
+
+import org.eclipse.jface.dialogs.*;
+import org.eclipse.swt.graphics.*;
+
+import ie.dcu.apps.ist.*;
+
+/**
+ * Root class for all application actions.
+ * 
+ * @author Kevin McGuinness
+ */
+public class AppAction extends ConfiguredAction {
+       
+       // Make easier for subclasses to set status
+       protected static final AppStatus Information = AppStatus.Information;
+       protected static final AppStatus Warning = AppStatus.Warning;
+       protected static final AppStatus Error = AppStatus.Error;
+       
+       // Logger
+       protected final Logger log = Logger.getLogger(getClass().getSimpleName());
+       
+       // Window
+       protected final AppWindow window;
+       
+       // Action manager
+       protected final ActionManager manager;
+       
+
+       public AppAction(ActionManager m) {
+               super(m.getProperties());
+               manager = m;
+               window = m.getWindow();
+       }
+       
+       
+       public AppAction(ActionManager m, int style) {
+               super(m.getProperties(), style);
+               manager = m;
+               window = m.getWindow();
+       }
+       
+       
+       @Override
+       public void arm() {
+               super.arm();
+               status(AppStatus.Information, getDescription());
+       }
+
+
+       @Override
+       public void disarm() {
+               super.disarm();
+               window.setStatus(null);
+       }
+
+
+       public String id() {
+               return getClass().getName();
+       }
+       
+       
+       protected Image icon(String key) {
+               String prop = string(key);
+               if (prop != null) {
+                       return window.getIcon(prop);
+               }
+               return null;
+       }
+
+
+       protected void error(String message) {
+               MessageDialog.openError(window.getShell(), "Error", message);
+       }
+
+
+       protected void error(String format, Object... args) {
+               error(String.format(format, args));
+       }
+
+
+       protected void warning(String message) {
+               MessageDialog.openWarning(window.getShell(), "Warning", message);
+       }
+
+
+       protected void warning(String format, Object... args) {
+               warning(String.format(format, args));
+       }
+
+
+       protected void info(String message) {
+               MessageDialog.openInformation(window.getShell(), "Information", message);
+       }
+
+
+       protected void info(String format, Object... args) {
+               info(String.format(format, args));
+       }
+
+
+       protected void log(Level level, String message, Throwable th) {
+               log.log(level, message, th);
+       }
+
+
+       protected String property(String key) {
+               return properties.getProperty(key);
+       }
+
+
+       protected void status(AppStatus s, String format, Object... args) {
+               window.status(s, format, args);
+       }
+
+
+       protected void status(String format, Object... args) {
+               status(Information, format, args);
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/ConfigureSegmenterAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/ConfigureSegmenterAction.java
new file mode 100644 (file)
index 0000000..5221928
--- /dev/null
@@ -0,0 +1,24 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.views.SegmentationView;
+
+/**
+ * Show the configure segmenter dialog.
+ * 
+ * @author Kevin McGuinness
+ */
+public class ConfigureSegmenterAction extends AppAction {
+
+       public ConfigureSegmenterAction(ActionManager m) {
+               super(m);
+       }
+
+       
+       @Override 
+       public void run() { 
+               SegmentationView view = window.getView();
+               if (view.canShowOptions()) {
+                       view.showSegmenterOptions();
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/ConfiguredAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/ConfiguredAction.java
new file mode 100644 (file)
index 0000000..24a33f0
--- /dev/null
@@ -0,0 +1,169 @@
+package ie.dcu.apps.ist.actions;
+
+import java.net.*;
+import java.util.*;
+import java.util.logging.*;
+
+import org.eclipse.jface.action.*;
+import org.eclipse.jface.resource.*;
+
+/**
+ * Hover Action configured from a properties file.
+ * 
+ * @author Kevin McGuinness
+ */
+public class ConfiguredAction extends HoverAction {
+       private static final Logger log = Logger.getLogger("ConfiguredAction");
+       
+       protected final Properties properties;
+       private final String id;
+       
+       
+       public ConfiguredAction(Properties properties) {
+               this(properties, null, AS_PUSH_BUTTON);
+       }
+       
+       
+       public ConfiguredAction(Properties properties, int style) {
+               this(properties, null, style);
+       }
+       
+       
+       public ConfiguredAction(Properties properties, String id, int style) {
+               super(null, style);
+               
+               assert (properties != null);
+               this.properties = properties;
+               
+               if (id != null) {
+                       this.id = id;
+               } else {
+                       this.id = getClass().getSimpleName();
+               }
+               
+               configure();
+       }
+
+       
+       private void configure() {
+               
+               // Set id
+               setId(id);
+
+               // Set text
+               setText(string("text"));
+               
+               // Set description
+               String description;
+               if ((description = string("description")) != null) {
+                       setDescription(description);
+               }
+               
+               // Set tooltip
+               String tooltip;
+               if ((tooltip = string("tooltip")) != null) {
+                       setToolTipText(tooltip);
+               }
+               
+               // Set accelerator
+               Integer keycode;
+               if ((keycode = accelerator("accelerator")) != null) {
+                       setAccelerator(keycode);
+               }
+       
+               // Set images
+               ImageDescriptor im;
+               
+               if ((im = image("image")) != null) {
+                       setImageDescriptor(im);
+               }
+               
+               if ((im = image("hoverImage")) != null) {
+                       setHoverImageDescriptor(im);
+               }
+               
+               if ((im = image("disabledImage")) != null) {
+                       setDisabledImageDescriptor(im);
+               }
+               
+               // Set status
+               Boolean status;
+               
+               if ((status = bool("checked") != null)) {
+                       setChecked(status);
+               }
+               
+               if ((status = bool("enabled") != null)) {
+                       setEnabled(status);
+               }
+       }
+       
+       
+       protected final Integer accelerator(String key) {
+               String value = string(key);
+               
+               if (value == null) {
+                       return null;
+               }
+               
+               int code = Action.convertAccelerator(value);
+               
+               if (code == 0) {
+                       log.warning("No accelerator: " + value);
+                       return null;
+               }
+               
+               if (code == -1) {
+                       log.warning("Not a valid accelerator keycode: " + value);
+                       return null;
+               }
+               
+               return code;
+       }
+       
+       
+       protected final Boolean bool(String key) {
+               String value = string(key);
+               
+               if (value == null) {
+                       return null;
+               }
+               
+               if (value.trim().equals("true")) {
+                       return true;
+               } else if (value.trim().equals("false")) {
+                       return false;
+               } else {
+                       log.warning("Not a boolean value: " + value);
+                       return null;
+               }
+       }
+       
+       
+       protected final ImageDescriptor image(String key) {
+               String url = string(key);
+               
+               if (url == null) {
+                       return null;
+               }
+               
+               try {
+                       return ImageDescriptor.createFromURL(new URL(url));
+                       
+               } catch (MalformedURLException e) {
+                       log.warning("Invalid URL for image " + url);
+                       return null;
+               }
+       }
+       
+       
+       protected final String string(String key) {
+               return properties.getProperty(key(key));
+       }
+       
+       
+       protected final String key(String name) {
+               return String.format("action.%s.%s", id, name);
+       }
+
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/CopyAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/CopyAction.java
new file mode 100644 (file)
index 0000000..1e7eb65
--- /dev/null
@@ -0,0 +1,100 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.views.SegmentationView;
+import ie.dcu.segment.SegmentationContext;
+import ie.dcu.segment.painters.SegmentationPainter;
+import ie.dcu.swt.*;
+
+import java.awt.Toolkit;
+import java.awt.datatransfer.*;
+import java.awt.image.BufferedImage;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Copy view to clipboard.
+ * 
+ * @author Kevin McGuinness
+ */
+public class CopyAction extends AppAction {
+       
+       public CopyAction(ActionManager m) {
+               super(m);
+       }
+
+       @Override 
+       public void run() { 
+               
+               if (window.hasContext()) {
+                       copy();
+               }
+       }
+
+       
+       private void copy() {
+               setClipboard(paintContext());
+               status("View copied to clipboard as image");
+       }
+       
+       
+       private static BufferedImage convert(Image image) {
+               BufferedImage im = ImageConverter.convert(image.getImageData());
+               image.dispose();
+               return im;
+       }
+
+
+       public void setClipboard(Image image) {
+               ImageSelection selection = new ImageSelection(convert(image));
+               Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
+               clip.setContents(selection, null);
+       }
+       
+       
+       
+       private Image paintContext() {
+               SegmentationView view = window.getView();
+               SegmentationContext ctx = window.getContext();
+               SegmentationPainter painter = view.getPainter();
+               ObservableImage im = createCompatibleImage(ctx);
+               painter.paint(ctx, im);
+               return im.getImage();
+       }
+       
+       
+       private ObservableImage createCompatibleImage(SegmentationContext ctx) {
+               Image im = new Image(Display.getCurrent(), ctx.getBounds());
+               return new ObservableImage(im);
+       }
+       
+       
+       private static class ImageSelection implements Transferable {
+               private BufferedImage image;
+
+               
+               public ImageSelection(BufferedImage image) {
+                       this.image = image;
+               }
+
+
+               public DataFlavor[] getTransferDataFlavors() {
+                       return new DataFlavor[] { DataFlavor.imageFlavor };
+               }
+
+
+               public boolean isDataFlavorSupported(DataFlavor flavor) {
+                       return DataFlavor.imageFlavor.equals(flavor);
+               }
+
+
+               public Object getTransferData(DataFlavor flavor) 
+                       throws UnsupportedFlavorException
+               {
+                       if (!DataFlavor.imageFlavor.equals(flavor)) {
+                               throw new UnsupportedFlavorException(flavor);
+                       }
+                       return image;
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/ExitAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/ExitAction.java
new file mode 100644 (file)
index 0000000..e6ee5c2
--- /dev/null
@@ -0,0 +1,37 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.*;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+
+/**
+ * Terminate the application.
+ * 
+ * @author Kevin McGuinness
+ */
+public class ExitAction extends AppAction {
+       public ExitAction(ActionManager m) {
+               super(m);
+       }
+
+       @Override 
+       public void run() {
+               if (confirmExit(window)) {
+                       window.close();
+                       System.exit(0);
+               }
+       }
+       
+       public static boolean confirmExit(AppWindow window) {
+               boolean confirm = window.getPrefs().get(
+                               Boolean.class, AppPrefs.Keys.CONFIRM_EXIT, true);
+               
+               if (confirm) {
+                       return MessageDialog.openConfirm(
+                                       window.getShell(), "Confirm", 
+                                       "Really exit the application?");
+               }
+               
+               return true;
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/ExportImageMapAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/ExportImageMapAction.java
new file mode 100644 (file)
index 0000000..54c78f7
--- /dev/null
@@ -0,0 +1,82 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.dialogs.ExportDialog;
+import ie.dcu.apps.ist.export.imagemap.*;
+import ie.dcu.segment.*;
+import ie.dcu.swt.ImageConverter;
+
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.logging.Level;
+
+import org.eclipse.swt.program.Program;
+
+/**
+ * Export segmentation results as HTML image maps
+ * 
+ * @author Kevin McGuinness
+ */
+public class ExportImageMapAction extends AppAction {
+
+       public ExportImageMapAction(ActionManager m) {
+               super(m);
+       }
+
+       @Override 
+       public void run() { 
+               
+               if (window.hasContext()) {
+                       
+                       // Get options from user
+                       ExportDialog dialog = new ExportDialog(window.getShell());
+                       ExportDialog.Result result = dialog.open();
+                       
+                       if (result != null) {
+                               
+                               // Grab image and mask
+                               SegmentationContext ctx = window.getContext();
+                               SegmentationMask mask = ctx.getMask();
+                               BufferedImage image = ImageConverter.convert(ctx.getImageData());
+                               
+                               // Setup exporter
+                               Exporter exporter = new Exporter(image, mask);
+                               exporter.setEffect(result.effect);
+                               exporter.setHtmlFile(result.html);
+                               exporter.setImageFile(result.image);
+                               exporter.setObjectLink(result.link);
+                               exporter.setExportShape(result.shape);
+                               exporter.setObjectDescription(result.description);
+                               
+                               // Export
+                               try {
+                                       exporter.export(result.folder);
+                               } catch (IOException e) {
+                                       handleError(e);
+                                       return;
+                               } catch (ExportException e) {
+                                       handleError(e);
+                                       return;
+                               } 
+                               
+                               if (result.open) {
+                                       File file = new File(result.folder, result.html);
+                                       Program program = Program.findProgram(".html");
+                                       if (program != null) {
+                                               program.execute(file.getAbsolutePath());
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       private void handleError(Exception e) {
+               log(Level.WARNING, "Error exporting view as HTML image map", e);
+               
+               // Show error dialog
+               error("Error exporting view as HTML image map: %s",  
+                               e.getLocalizedMessage());
+               
+               // Set status message
+               status(Error, "Error exporting view as HTML image map");
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/ExportTransparentPNGAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/ExportTransparentPNGAction.java
new file mode 100644 (file)
index 0000000..1315e33
--- /dev/null
@@ -0,0 +1,148 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.segment.*;
+import ie.dcu.swt.SwtUtils;
+import ie.dcu.util.FileUtils;
+
+import java.io.*;
+import java.util.logging.Level;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.FileDialog;
+
+public class ExportTransparentPNGAction extends AppAction {
+       
+private static final String DEFAULT_SUFFIX = ".png";
+       
+       private FileDialog dialog;
+       private String directory;
+
+       public ExportTransparentPNGAction(ActionManager m) {
+               super(m);
+       }
+       
+       @Override 
+       public void run() { 
+               if (window.hasContext()) {
+                       File file = getFile();
+                       if (file != null) {
+                               directory = file.getParent();
+                               export(file);
+                       }
+               }               
+       }
+
+
+       private void export(File file) {
+               ImageData im = createSemiTransparentImage();
+               try {
+                       SwtUtils.saveImage(im, file);
+               } catch (IOException e) {
+                       handleError(file, e);
+               }
+       }
+       
+       
+       private ImageData createSemiTransparentImage() {
+               SegmentationContext ctx = window.getContext();
+               ImageData image = ctx.getImageData();
+               SegmentationMask mask = ctx.getMask();
+               ImageData result = new ImageData(image.width, image.height, 32, image.palette);
+               
+               int[] pixels = new int[image.width];
+               byte[] alphas = new byte[image.width];
+               
+               for (int y = 0; y < image.height; y++) {
+                       image.getPixels(0, y, image.width, pixels, 0);
+                       
+                       int offset = y * mask.cols;
+                       for (int i = 0; i < mask.cols; i++) {
+                               if (mask.values[i+offset] == SegmentationMask.BACKGROUND) {
+                                       alphas[i] = (byte) 0x00;
+                               } else {
+                                       alphas[i] = (byte) 0xff;
+                               }
+                       }
+                       
+                       result.setPixels(0, y, image.width, pixels, 0);
+                       result.setAlphas(0, y, image.width, alphas, 0);
+               }
+               
+               return result;
+       }
+
+       
+       private void handleError(File file, IOException e) {
+               // Log
+               log(Level.WARNING, "Error exporting view as image", e);
+               
+               // Show error dialog
+               error("Error exporting view as image %s: %s", 
+                               file.getName(), e.getLocalizedMessage()
+               );
+               
+               // Set status message
+               status(Error, "Error exporting view as image %s", file.getName());
+       }
+
+       
+       private File getFile() {
+               createExportDialog();
+               
+               String path = dialog.open();
+               if (path != null) {
+                       return checkFile(path);
+               }
+               
+               return null;
+       }
+       
+       
+       private File checkFile(String path) {
+               File file = new File(path);
+
+               if (SwtUtils.getImageFormat(file) != -1) {
+                       return file;
+               } 
+               
+               // Unknown file extension, so assume jpg
+               return new File(FileUtils.replaceExtension(path, DEFAULT_SUFFIX));
+       }
+
+       
+       private void createExportDialog() {
+               if (dialog == null) {
+                       dialog = new FileDialog(window.getShell(), SWT.SAVE | SWT.SHEET);
+                       dialog.setText("Export Transparent PNG");
+                       dialog.setFilterExtensions(new String[]{"*.png"});
+                       dialog.setFilterNames(new String[]{"PNG Images"});
+               }
+               
+               dialog.setFileName(getFileName());
+               
+               String dir = getDirectory();
+               if (dir != null) {
+                       // Unfortunately this is buggy on SWT/GTK and
+                       // the filter path isin't always set :'-(
+                       dialog.setFilterPath(dir);
+               }
+       }
+       
+       private String getFileName() {
+               File file = window.getContext().getFile();
+               return FileUtils.replaceExtension(file.getName(), DEFAULT_SUFFIX);
+       }
+       
+       
+       private String getDirectory() {
+               if (directory == null) {
+                       File folder = window.getContext().getFolder();
+                       directory = (folder != null) ? 
+                                       directory = folder.getAbsolutePath() : null;
+               }
+               
+               return directory;
+       }
+       
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/ExportViewAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/ExportViewAction.java
new file mode 100644 (file)
index 0000000..a6ca7b5
--- /dev/null
@@ -0,0 +1,162 @@
+package ie.dcu.apps.ist.actions;
+
+
+import ie.dcu.apps.ist.views.SegmentationView;
+import ie.dcu.segment.SegmentationContext;
+import ie.dcu.segment.painters.SegmentationPainter;
+import ie.dcu.swt.*;
+import ie.dcu.util.FileUtils;
+
+import java.io.*;
+import java.util.logging.Level;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.*;
+
+
+/**
+ * Export current view as image.
+ * 
+ * @author Kevin McGuinness
+ */
+public class ExportViewAction extends AppAction {
+       
+       private static final String DEFAULT_SUFFIX = ".png";
+       
+       private FileDialog dialog;
+       private String directory;
+       
+       public ExportViewAction(ActionManager m) {
+               super(m);
+       }
+
+       @Override 
+       public void run() { 
+               if (window.hasContext()) {
+                       File file = getFile();
+                       if (file != null) {
+                               directory = file.getParent();
+                               export(file);
+                       }
+               }               
+       }
+
+
+       private void export(File file) {
+               Image im = paintContext();
+               
+               try {
+                       SwtUtils.saveImage(im, file);
+                       status("View successfully exported as %s", file.getName());
+                       
+               } catch (IOException e) {
+               
+                       handleError(file, e);
+                       
+               } finally {
+                       
+                       im.dispose();
+               }
+       }
+
+       
+       private void handleError(File file, IOException e) {
+               // Log
+               log(Level.WARNING, "Error exporting view as image", e);
+               
+               // Show error dialog
+               error("Error exporting view as image %s: %s", 
+                               file.getName(), e.getLocalizedMessage()
+               );
+               
+               // Set status message
+               status(Error, "Error exporting view as image %s", file.getName());
+       }
+
+       
+       private File getFile() {
+               createExportDialog();
+               
+               String path = dialog.open();
+               if (path != null) {
+                       return checkFile(path);
+               }
+               
+               return null;
+       }
+       
+       
+       private File checkFile(String path) {
+               File file = new File(path);
+
+               if (SwtUtils.getImageFormat(file) != -1) {
+                       return file;
+               } 
+               
+               // Unknown file extension, so assume jpg
+               return new File(FileUtils.replaceExtension(path, DEFAULT_SUFFIX));
+       }
+
+       
+       private void createExportDialog() {
+               if (dialog == null) {
+                       dialog = new FileDialog(window.getShell(), SWT.SAVE | SWT.SHEET);
+                       dialog.setText(property("ExportViewAction.dialog.text"));
+                       dialog.setFilterExtensions(getFilters());
+                       dialog.setFilterNames(getFilterNames());
+               }
+               
+               dialog.setFileName(getFileName());
+               
+               String dir = getDirectory();
+               if (dir != null) {
+                       // Unfortunately this is buggy on SWT/GTK and
+                       // the filter path isin't always set :'-(
+                       dialog.setFilterPath(dir);
+               }
+       }
+       
+       private String getFileName() {
+               File file = window.getContext().getFile();
+               return FileUtils.replaceExtension(file.getName(), DEFAULT_SUFFIX);
+       }
+       
+       
+       private String getDirectory() {
+               if (directory == null) {
+                       File folder = window.getContext().getFolder();
+                       directory = (folder != null) ? 
+                                       directory = folder.getAbsolutePath() : null;
+               }
+               
+               return directory;
+       }
+       
+       
+       
+       private String[] getFilters() {
+               return new String[] { property("ExportViewAction.dialog.filter.exts") };
+       }
+       
+       
+       private String[] getFilterNames() {
+               return new String[] { property("ExportViewAction.dialog.filter.text") };
+       }
+       
+       
+       private Image paintContext() {
+               SegmentationView view = window.getView();
+               SegmentationContext ctx = window.getContext();
+               SegmentationPainter painter = view.getPainter();
+               ObservableImage im = createCompatibleImage(ctx);
+               painter.paint(ctx, im);
+               return im.getImage();
+       }
+       
+       
+       private ObservableImage createCompatibleImage(SegmentationContext ctx) {
+               Image im = new Image(Display.getCurrent(), ctx.getBounds());
+               return new ObservableImage(im);
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/HelpAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/HelpAction.java
new file mode 100644 (file)
index 0000000..6905dd6
--- /dev/null
@@ -0,0 +1,126 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.swt.layout.LayoutFactory;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Show a help dialog.
+ * 
+ * @author Kevin McGuinness
+ */
+public class HelpAction extends AppAction {
+       
+       private HelpBox dialog;
+       
+       
+       public HelpAction(ActionManager m) {
+               super(m);
+       }
+
+       
+       @Override 
+       public void run() { 
+               if (dialog == null) {
+                       dialog = new HelpBox();
+               }
+               
+               if (dialog.available()) {
+                       dialog.open();
+               } else {
+                       info("Help browser unavailable on this system");
+               }
+       }
+       
+       
+       /**
+        * Help dialog box, just wraps a browser.
+        */
+       private class HelpBox {
+               private Shell shell;
+               private Composite content;
+               private Browser browser;
+               
+               
+               public HelpBox() {
+                       createShell();
+                       createContent();
+               }
+
+
+               private void createShell() {
+                       shell = new Shell(window.getShell(), SWT.SHELL_TRIM);
+                       
+                       // Prevent the shell from disposing on close
+                       shell.addShellListener(new ShellAdapter() {
+                               public void shellClosed(ShellEvent evt) {
+                                       evt.doit = false;
+                                       close();
+                               }
+                       });
+                       
+                       // Use a fill layout
+                       shell.setLayout(new GridLayout());
+                       
+                       // Set size and title
+                       shell.setSize(640, 480);
+                       shell.setText("Help");
+               }
+
+
+               private void createContent() {
+                       // Create content pane
+                       content = new Composite(shell, SWT.BORDER);
+                       content.setLayout(new FillLayout());
+                       content.setLayoutData(LayoutFactory.createGridData());
+                       
+                       // Add browser widget
+                       try {
+                               browser = new Browser(content, SWT.NONE);
+                       } catch (SWTError e) {
+                               
+                               // Log warning and return
+                               log.warning("Browser unavailable: " + e.getMessage());
+                               browser = null;
+                               return;
+                       }
+                       
+                       // Go to help home page
+                       home();
+               }
+
+
+               public void home() {
+                       String urlString = string("helpURL");
+                       if (urlString != null) {
+                               go(urlString);
+                       } else {
+                               browser.setText("Help file is unavailable");
+                       }
+               }
+               
+               
+               public void go(String url) {
+                       browser.setUrl(url);
+               }
+                               
+               
+               public boolean available() {
+                       return browser != null;
+               }
+               
+               
+               public void open() {
+                       shell.setVisible(true);
+               }
+               
+               
+               public void close() {
+                       shell.setVisible(false);
+               }
+       }       
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/HoverAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/HoverAction.java
new file mode 100644 (file)
index 0000000..cf933bc
--- /dev/null
@@ -0,0 +1,88 @@
+package ie.dcu.apps.ist.actions;
+
+import org.eclipse.jface.action.*;
+import org.eclipse.jface.resource.*;
+
+/**
+ * Default implementation of {@link IHoverAction}. 
+ * 
+ * @author Kevin McGuinness
+ */
+public class HoverAction extends Action implements IHoverAction {
+       private boolean armed = false;
+       
+       /**
+        * Creates a new action with no text and no image. Configure the action later
+        * using the set methods.
+        */
+       public HoverAction() {
+               super();
+       }
+
+
+       /**
+        * Creates a new action with the given text and no image.
+        * 
+        * @param text
+        *          the string used as the text for the action, or <code>null</code>
+        *          if there is no text
+        */
+       public HoverAction(String text) {
+               super(text);
+       }
+
+
+       /**
+        * Creates a new action with the given text and image.
+        * 
+        * @param text
+        *          the action's text, or <code>null</code> if there is no text
+        * @param image
+        *          the action's image, or <code>null</code> if there is no image
+        */
+       public HoverAction(String text, ImageDescriptor image) {
+               super(text, image);
+       }
+
+
+       /**
+        * Creates a new action with the given text and style.
+        * 
+        * @param text
+        *            the action's text, or <code>null</code> if there is no text.
+        * @param style
+        *            one of 
+        *            <code>AS_PUSH_BUTTON</code>,
+        *            <code>AS_CHECK_BOX</code>, 
+        *            <code>AS_DROP_DOWN_MENU</code>,
+        *            <code>AS_RADIO_BUTTON</code>, and
+        *            <code>AS_UNSPECIFIED</code>.
+        */
+       public HoverAction(String text, int style) {
+               super(text, style);
+       }
+
+
+       /**
+        * Sets the armed property to <code>true</code>.
+        */
+       public void arm() {
+               armed = true;
+       }
+
+
+       /**
+        * Sets the armed property to <code>false</code>.
+        */
+       public void disarm() {
+               armed = false;
+       }
+
+
+       /**
+        * Returns <code>true</code> if armed.
+        */
+       public boolean isArmed() {
+               return armed;
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/HoverMenuManager.java b/image_annotation/src/ie/dcu/apps/ist/actions/HoverMenuManager.java
new file mode 100644 (file)
index 0000000..d3b051a
--- /dev/null
@@ -0,0 +1,149 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.widgets.ImageMenuManager;
+
+import java.net.URL;
+import java.util.*;
+
+import org.eclipse.jface.action.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Menu Manager that notifies instances of IHoverAction when they are armed and
+ * disarmed.
+ * 
+ * @author Kevin McGuinness
+ */
+public class HoverMenuManager extends ImageMenuManager  {
+       
+       /**
+        * Stores items that have hover listeners added to them. 
+        */
+       private final Set<MenuItem> hoverItems = new HashSet<MenuItem>();
+       
+       
+       /**
+        * Create hover menu manager.
+        */
+       public HoverMenuManager() {
+               init();
+       }
+
+       
+       /**
+        * Create hover menu manager with id and text.
+        * 
+        * @param text
+        *          the text for the menu, or <code>null</code> if none.
+        * @param imageURL
+        *          the menu image url, or <code>null</code>.
+        */
+       public HoverMenuManager(String text, URL imageURL) {
+               super(text, imageURL);
+               init();
+       }
+
+
+  /**
+        * Create hover menu manager text.
+        * 
+        * @param text
+        *          the text for the menu, or <code>null</code> if none.
+        */
+       public HoverMenuManager(String text) {
+               super(text);
+               init();
+       }
+
+       
+       private void init() {
+               addMenuListener(menuListener);
+       }
+
+
+       private void addHoverListeners() {
+               Menu menu = getMenu();
+               for (MenuItem item : menu.getItems()) {
+                       addHoverListener(item);
+               }
+       }
+       
+
+       private void addHoverListener(MenuItem item) {
+               IHoverAction action = getHoverAction(item);
+               if (action != null) {
+                       addHoverListener(item, action);
+               }
+       }
+
+       
+       private void addHoverListener(MenuItem item, IHoverAction action) {
+               if (!hoverItems.contains(item)) {
+                       item.addArmListener(new HoverListener(action));
+                       hoverItems.add(item);
+               }
+       }
+       
+       
+       private void disarmAll() {
+               Menu menu = getMenu();
+               for (MenuItem item : menu.getItems()) {
+                       disarm(item);
+               }
+       }
+       
+       
+       private void disarm(MenuItem item) {
+               IHoverAction action = getHoverAction(item);
+               if (action != null) {
+                       disarm(action);
+               }
+       }
+
+
+       private void disarm(IHoverAction action) {
+               if (action.isArmed()) {
+                       action.disarm();
+               }
+       }
+       
+       
+       private IHoverAction getHoverAction(MenuItem item) {
+               Object data = item.getData();
+               if (data instanceof ActionContributionItem) {
+                       IAction action = ((ActionContributionItem) data).getAction();
+                       
+                       if (action instanceof IHoverAction) {
+                               return (IHoverAction) action;
+                       }
+               }
+               return null;
+       }
+
+
+       private IMenuListener menuListener = new IMenuListener2() {
+               public void menuAboutToShow(IMenuManager manager) {
+                       addHoverListeners();
+               }
+
+               public void menuAboutToHide(IMenuManager manager) {
+                       disarmAll();
+               }               
+       };
+       
+       
+       private final class HoverListener implements ArmListener {
+               private final IHoverAction action;
+
+               public HoverListener(IHoverAction action) {
+                       this.action = action;
+               }
+
+               
+               public void widgetArmed(ArmEvent e) {
+                       disarmAll();
+                       action.arm();
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/IHoverAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/IHoverAction.java
new file mode 100644 (file)
index 0000000..cac72be
--- /dev/null
@@ -0,0 +1,34 @@
+package ie.dcu.apps.ist.actions;
+
+import org.eclipse.jface.action.*;
+
+/**
+ * Extension of IAction that supports arming when the mouse hovers over the
+ * item. This may be useful for displaying descriptions of menu items in the
+ * status bar, for example. To use hover actions the {@link HoverMenuManager}
+ * must be used.
+ * 
+ * @author Kevin McGuinness
+ */
+public interface IHoverAction extends IAction {
+       
+       
+       /**
+        * Executed when the action is hovered/armed.
+        */
+       public void arm();
+       
+       
+       /**
+        * Executed when the action is de-hovered/disarmed.
+        */
+       public void disarm();
+       
+       
+       /**
+        * Query if the action is armed.
+        * 
+        * @return <code>true</code> if armed.
+        */
+       public boolean isArmed();
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/NextAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/NextAction.java
new file mode 100644 (file)
index 0000000..900618b
--- /dev/null
@@ -0,0 +1,122 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.actions;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Jump to the next image in the directory
+ * 
+ * @author Kevin McGuinness
+ */
+public class NextAction extends AppAction {
+       // Supported file extensions
+       static final String EXTENSIONS = "jpg;jpeg;png;gif;bmp;ctx";
+       
+       private final java.io.FileFilter imageFilter;
+
+       
+       public NextAction(ActionManager m) {
+               super(m);
+               
+               // Create an image file filter
+               imageFilter = new SimpleFileFilter(EXTENSIONS);
+       }
+
+       
+       @Override 
+       public void run() {
+               if (window.hasContext()) {
+                       // Get currently opened file
+                       File file = window.getContext().getFile();
+                       
+                       // Find the one after & open it
+                       File next = findNext(file);
+                       if (next != null) {
+                               manager.get(OpenAction.class).open(next);
+                       }
+               }
+       }
+       
+       
+       private File findNext(File file) {
+               File dir = file.getParentFile();
+               
+               if (dir != null) {
+                       
+                       // List the images
+                       File[] files = dir.listFiles(imageFilter);
+                       
+                       // Need at least one
+                       if (files.length > 1) {
+                               
+                               // Search for ourself...
+                               for (int i = 0; i < files.length; i++) {
+                                       
+                                       if (files[i].equals(file)) {
+                                               
+                                               // Use next file (wrap back to first)
+                                               return files[(i+1)%files.length];
+                                       }
+                               }
+                       }
+               }
+               
+               return null;
+       }
+       
+}
+
+class SimpleFileFilter implements java.io.FileFilter {
+       
+       /**
+        * Holds the list of extensions. It is expected it will be quite
+        * short, so we use an ArrayList.
+        */
+       private final ArrayList<String> extensions;
+       
+       
+       /**
+        * Construct a simple file extension filter based on a semicolon separated
+        * list of file extensions.
+        * 
+        * @param extensions
+        *          A list of file extensions (ex. jpeg;jpg;png)
+        */
+       public SimpleFileFilter(String extensions) {
+               String[] exts = extensions.split(";");
+               this.extensions = new ArrayList<String>(exts.length);
+               
+               for (String s : exts) {
+                       if ((s = s.trim()).length() != 0) {
+                               if (s.startsWith("*")) {
+                                       s = s.substring(1);
+                               }
+                               
+                               if (!s.startsWith(".")) {
+                                       s = "." + s;
+                               }
+                               
+                               this.extensions.add(s);
+                       }
+               }
+       }
+       
+
+       public boolean accept(File pathname) {
+               if (pathname.isFile()) {
+                       String name = pathname.getName();
+                       
+                       // List of extensions should be fairly short..
+                       for (String ext : extensions) {
+                               if (name.endsWith(ext)) {
+                                       return true;
+                               }
+                       }
+               }
+               
+               return false;
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/OpenAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/OpenAction.java
new file mode 100644 (file)
index 0000000..823f176
--- /dev/null
@@ -0,0 +1,110 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.*;
+import ie.dcu.segment.SegmentationContext;
+
+import java.io.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Open an image or segmentation context.
+ * 
+ * @author Kevin McGuinness
+ */
+public class OpenAction extends AppAction {
+
+       private FileDialog dialog;
+       
+       public OpenAction(ActionManager m) {
+               super(m);
+       }
+       
+
+       @Override
+       public void run() {
+               File file = getFile();
+               if (file != null) {
+                       open(file);
+               }
+       }
+       
+
+       public boolean open(File file) {
+               String name = file.getName();
+               try {
+                       if (SegmentationContext.isContextFile(file)) {
+                       
+                               // Load context
+                               window.setContext(SegmentationContext.load(file));
+                               status("Opened segmentation context %s successfully", name);
+                       } else {
+                       
+                               // Create context
+                               window.setContext(SegmentationContext.create(file));
+                               status("Opened image file %s successfully", name);
+                       }
+                       
+                       // Save history
+                       AppRecentFiles.getInstance().add(file);
+                       
+                       // Ok
+                       return true;
+                       
+               } catch (IOException e) {
+                       
+                       handleError(file, e);
+                       status(Warning, "Proplem opening file %s", name);
+               
+                       return false;
+               }
+       }
+
+
+       private void handleError(File file, IOException e) {
+
+               // Get appropriate message
+               String message = e.getCause() == null ? e.getLocalizedMessage() :
+                       e.getCause().getLocalizedMessage();
+               
+               // Log warning
+               log.warning(String.format(
+                               "Unable to open %s\n Problem: %s", file, message
+               ));
+
+               // Show warning dialog
+               warning("Unable to open %s:\n%s", file.getName(), message);
+       }
+
+
+       private void createOpenDialog() {
+               // Create dialog if necessary
+               if (dialog == null) {
+                       dialog = new FileDialog(window.getShell(), SWT.OPEN | SWT.SHEET);
+                       dialog.setText(property("OpenAction.dialog.text"));
+                       dialog.setFilterExtensions(getFilters());
+                       dialog.setFilterNames(getFilterNames());
+               }
+       }
+       
+       private String[] getFilters() {
+               return new String[] { property("OpenAction.dialog.filter.exts") };
+       }
+       
+       private String[] getFilterNames() {
+               return new String[] { property("OpenAction.dialog.filter.text") };
+       }
+       
+       
+       private File getFile() {
+               createOpenDialog();
+               
+               String path = dialog.open();
+               if (path != null) {
+                       return new File(path);
+               }
+               
+               return null;
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/OpenExperimentAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/OpenExperimentAction.java
new file mode 100644 (file)
index 0000000..2e27dd4
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.exp.*;
+
+import java.io.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Open an experiment file and switch to experiment mode.
+ * 
+ * @author Kevin McGuinness
+ */
+public class OpenExperimentAction extends AppAction {
+       
+       private FileDialog dialog;
+       
+
+       public OpenExperimentAction(ActionManager m) {
+               super(m);
+       }
+
+       
+       @Override
+       public void run() {
+               File file = getFile();
+               if (file != null) {
+                       open(file);
+               }
+       }
+       
+       
+       private void open(File file) {
+               try {
+                       Experiment ex = ExperimentFactory.getInstance().load(file);
+                       window.setExperiment(ex);
+                       
+               } catch (IOException ex) {
+                       handleError(file, ex);
+               } catch (FormatException ex) {
+                       handleError(file, ex);
+               }
+       }
+       
+       
+       private void handleError(File file, Exception ex) {
+               // Get appropriate message
+               String mesg = ex.getMessage();
+               
+               // Log warning
+               log.warning(String.format(
+                               "Unable to open experiment file %s\n Problem: %s", file, mesg
+               ));
+
+               // Show warning dialog
+               warning("Unable to open experiment file %s:\n%s", file.getName(), mesg);
+       }
+
+
+       private File getFile() {
+               createOpenDialog();
+               
+               String path = dialog.open();
+               if (path != null) {
+                       return new File(path);
+               }
+               
+               return null;
+       }
+       
+       
+       private void createOpenDialog() {
+               // Create dialog if necessary
+               if (dialog == null) {
+                       dialog = new FileDialog(window.getShell(), SWT.OPEN | SWT.SHEET);
+                       dialog.setText(property("OpenExperimentAction.dialog.text"));
+                       dialog.setFilterExtensions(getFilters());
+                       dialog.setFilterNames(getFilterNames());
+               }
+       }
+       
+       private String[] getFilters() {
+               return new String[] { 
+                               property("OpenExperimentAction.dialog.filter.exts") 
+               };
+       }
+       
+       private String[] getFilterNames() {
+               return new String[] { 
+                               property("OpenExperimentAction.dialog.filter.text") 
+               };
+       }
+       
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/OpenRecentAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/OpenRecentAction.java
new file mode 100644 (file)
index 0000000..299117e
--- /dev/null
@@ -0,0 +1,25 @@
+package ie.dcu.apps.ist.actions;
+
+import java.io.*;
+
+/**
+ * Action to open a recent file.
+ * 
+ * @author Kevin McGuinness
+ */
+public class OpenRecentAction extends AppAction {
+       private final File file;
+
+       public OpenRecentAction(ActionManager m, File file) {
+               super(m);
+               this.file = file;
+               setText(file.getName());
+               String path = file.getAbsolutePath();
+               setToolTipText(path);
+               setDescription(String.format("Open file %s", path));
+       }
+       
+       public void run() {
+               manager.get(OpenAction.class).open(file);
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/PreferencesAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/PreferencesAction.java
new file mode 100644 (file)
index 0000000..1ccfc38
--- /dev/null
@@ -0,0 +1,24 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.dialogs.*;
+
+/**
+ * Show preferences dialog box.
+ * 
+ * @author Kevin McGuinness
+ */
+public class PreferencesAction extends AppAction {
+       private PrefsDialog dialog;
+       
+       public PreferencesAction(ActionManager m) {
+               super(m);
+       }
+
+       
+       public void run() { 
+               if (dialog == null) {
+                       dialog = new PrefsDialog(window);
+               }
+               dialog.open();
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/PreviousAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/PreviousAction.java
new file mode 100644 (file)
index 0000000..4bfb907
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.actions;
+
+import java.io.*;
+
+/**
+ * Jump to previous file in current directory.
+ * 
+ * @author Kevin McGuinness
+ */
+public class PreviousAction extends AppAction {
+       private final java.io.FileFilter imageFilter;
+
+
+       public PreviousAction(ActionManager m) {
+               super(m);
+               
+               // Create an image file filter
+               imageFilter = new SimpleFileFilter(NextAction.EXTENSIONS);
+       }
+       
+       
+       @Override 
+       public void run() {
+               if (window.hasContext()) {
+                       // Get currently opened file
+                       File file = window.getContext().getFile();
+                       
+                       // Find the one before & open it
+                       File next = findPrevious(file);
+                       if (next != null) {
+                               manager.get(OpenAction.class).open(next);
+                       }
+               }
+       }
+       
+
+       
+       private File findPrevious(File file) {
+               File dir = file.getParentFile();
+               
+               if (dir != null) {
+                       
+                       // List the images
+                       File[] files = dir.listFiles(imageFilter);
+                       
+                       // Need at least one
+                       if (files.length > 1) {
+                               
+                               // Search for ourself...
+                               for (int i = 0; i < files.length; i++) {
+                                       
+                                       if (files[i].equals(file)) {
+                                               
+                                               // Use previous file (wrap back to last)
+                                               return files[(i > 0) ? i - 1 : files.length - 1];
+                                       }
+                               }
+                       }
+               }
+               
+               return null;
+       }
+
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/PrintAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/PrintAction.java
new file mode 100644 (file)
index 0000000..3645631
--- /dev/null
@@ -0,0 +1,107 @@
+package ie.dcu.apps.ist.actions;
+
+
+import ie.dcu.apps.ist.views.SegmentationView;
+import ie.dcu.segment.SegmentationContext;
+import ie.dcu.segment.painters.SegmentationPainter;
+import ie.dcu.swt.ObservableImage;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.printing.*;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Send current view to printer.
+ * 
+ * @author Kevin McGuinness
+ */
+public class PrintAction extends AppAction {
+       
+       private static final String JOB_NAME = "Interactive Segmentation Tool";
+       private PrintDialog dialog;
+       
+       public PrintAction(ActionManager m) {
+               super(m);
+       }
+
+       @Override 
+       public void run() { 
+               if (window.hasContext()) {
+                       status("Printing...");
+                       PrinterData data = getPrintData();
+                       if (data != null) {
+                               print(data);
+                               status("Printing complete");
+                       } else {
+                               status(null);
+                       }
+               }
+       }
+       
+       
+       private PrinterData getPrintData() {
+               createPrintDialog();
+               return dialog.open();
+       }
+
+
+       private void print(PrinterData data) {
+               Printer printer = new Printer(data);
+               try {
+                       print(printer);
+                       
+               } finally {
+                       printer.dispose();
+               }
+       }
+
+
+       private void print(Printer printer) {
+               if (printer.startJob(JOB_NAME)) {
+                       if (printer.startPage()) {
+                               GC gc = new GC(printer);
+                               try {
+                                       paint(gc, printer);
+                               } finally {
+                                       gc.dispose();
+                               }
+                               printer.endPage();
+                       }
+                       printer.endJob();
+               }
+       }
+
+       
+       private void paint(GC gc, Printer printer) {
+               Image im = paintContext();
+               try {
+                       gc.drawImage(im, 30, 30);
+               } finally {
+                       im.dispose();
+               }
+       }
+       
+
+       private void createPrintDialog() {
+               if (dialog == null) {
+                       dialog = new PrintDialog(window.getShell(), SWT.SHEET);
+               }
+       }
+       
+       
+       private Image paintContext() {
+               SegmentationView view = window.getView();
+               SegmentationContext ctx = window.getContext();
+               SegmentationPainter painter = view.getPainter();
+               ObservableImage im = createCompatibleImage(ctx);
+               painter.paint(ctx, im);
+               return im.getImage();
+       }
+       
+       
+       private ObservableImage createCompatibleImage(SegmentationContext ctx) {
+               Image im = new Image(Display.getCurrent(), ctx.getBounds());
+               return new ObservableImage(im);
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/RedoAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/RedoAction.java
new file mode 100644 (file)
index 0000000..4e84880
--- /dev/null
@@ -0,0 +1,23 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.views.SegmentationView;
+
+
+/**
+ * Redo last annotation action.
+ * 
+ * @author Kevin McGuinness
+ */
+public class RedoAction extends AppAction {
+       public RedoAction(ActionManager m) {
+               super(m);
+       }
+
+       @Override 
+       public void run() {
+               SegmentationView view = window.getView();
+               if (view.canRedo()) {
+                       view.redo();
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/SaveAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/SaveAction.java
new file mode 100644 (file)
index 0000000..e652d28
--- /dev/null
@@ -0,0 +1,120 @@
+package ie.dcu.apps.ist.actions;
+
+import java.io.*;
+import java.util.logging.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Save segmentation context.
+ * 
+ * @author Kevin McGuinness
+ */
+public class SaveAction extends AppAction {
+       
+       private FileDialog dialog;
+
+       public SaveAction(ActionManager m) {
+               super(m);
+       }
+
+       
+       @Override
+       public void run() {
+               
+               if (window.hasContext()) {
+                       
+                       File file;
+                       if (window.hasContextFile()) {
+                               file = window.getContextFile();
+                       } else {
+                               file = getFile();
+                       }
+                       
+                       if (file != null) {
+                               save(file);
+                       }
+               }
+       }
+       
+
+       private void createSaveDialog() {
+               if (dialog == null) {
+                       dialog = new FileDialog(window.getShell(), SWT.SAVE | SWT.SHEET);
+                       dialog.setText(property("SaveAction.dialog.text"));
+                       dialog.setFilterExtensions(getFilters());
+                       dialog.setFilterNames(getFilterNames());
+                       
+                       String dir = getDirectory();
+                       if (dir != null) {
+                               dialog.setFilterPath(dir);
+                       }
+               }
+               
+               dialog.setFileName(getFileName());
+       }
+       
+       
+       private String getDirectory() {
+               File folder = window.getContext().getFolder();
+               if (folder != null) {
+                       return folder.getAbsolutePath();
+               }
+               
+               return null;
+       }
+       
+       
+       private String getFileName() {
+               return window.getContext().getDefaultFilename();
+       }
+       
+       
+       private String[] getFilters() {
+               return new String[] { property("SaveAction.dialog.filter.exts") };
+       }
+       
+       
+       private String[] getFilterNames() {
+               return new String[] { property("SaveAction.dialog.filter.text") };
+       }
+
+       
+       private File getFile() {
+               createSaveDialog();
+               
+               String path = dialog.open();
+               if (path != null) {
+                       return new File(path);
+               }
+               
+               return null;
+       }
+       
+       
+       private void save(File file) {
+               try {
+                       window.getContext().save(file);
+                       window.updateWindowTitle();
+                       status("Saved context %s successfully", file.getName());
+               } catch (IOException e) {
+                       handleError(file, e);
+               }
+       }
+
+
+       private void handleError(File file, IOException e) {
+               
+               // Log
+               log(Level.SEVERE, "Error saving file", e);
+               
+               // Show error dialog
+               error("Error saving segmentation context %s: %s", 
+                               file.getName(), e.getLocalizedMessage()
+               );
+               
+               // Set status message
+               status(Error, "Error saving segmentation context %s", file.getName());
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/SaveAsAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/SaveAsAction.java
new file mode 100644 (file)
index 0000000..7db1c26
--- /dev/null
@@ -0,0 +1,112 @@
+package ie.dcu.apps.ist.actions;
+
+import java.io.*;
+import java.util.logging.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Save segmentation context as.
+ * 
+ * @author Kevin McGuinness
+ */
+public class SaveAsAction extends AppAction {
+       
+       private FileDialog dialog;
+
+       public SaveAsAction(ActionManager m) {
+               super(m);
+       }
+       
+       @Override
+       public void run() {             
+               if (window.hasContext()) {
+                       File file = getFile();
+                       if (file != null) {
+                               save(file);
+                       }
+               }
+       }
+       
+       
+       private void createSaveDialog() {
+               if (dialog == null) {
+                       dialog = new FileDialog(window.getShell(), SWT.SAVE | SWT.SHEET);
+                       dialog.setText(property("SaveAction.dialog.text"));
+                       dialog.setFilterExtensions(getFilters());
+                       dialog.setFilterNames(getFilterNames());
+                       
+                       String dir = getDirectory();
+                       if (dir != null) {
+                               dialog.setFilterPath(dir);
+                       }
+               }
+               
+               dialog.setFileName(getFileName());
+       }
+       
+       
+       private String getDirectory() {
+               File folder = window.getContext().getFolder();
+               if (folder != null) {
+                       return folder.getAbsolutePath();
+               }
+               
+               return null;
+       }
+       
+       
+       
+       private String getFileName() {
+               return window.getContext().getDefaultFilename();
+       }
+       
+       
+       private String[] getFilters() {
+               return new String[] { property("SaveAction.dialog.filter.exts") };
+       }
+       
+       
+       private String[] getFilterNames() {
+               return new String[] { property("SaveAction.dialog.filter.text") };
+       }
+       
+       
+       private File getFile() {
+               createSaveDialog();
+               
+               String path = dialog.open();
+               if (path != null) {
+                       return new File(path);
+               }
+               
+               return null;
+       }
+       
+       
+       private void save(File file) {
+               try {
+                       window.getContext().save(file);
+                       window.updateWindowTitle();
+                       status("Saved context %s successfully", file.getName());
+               } catch (IOException e) {
+                       handleError(file, e);
+               }
+       }
+       
+       
+       private void handleError(File file, IOException e) {
+               
+               // Log
+               log(Level.SEVERE, "Error saving file", e);
+               
+               // Show error dialog
+               error("Error saving segmentation context %s: %s", 
+                               file.getName(), e.getLocalizedMessage()
+               );
+               
+               // Set status message
+               status(Error, "Error saving segmentation context %s", file.getName());
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/SelectSegmenterAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/SelectSegmenterAction.java
new file mode 100644 (file)
index 0000000..485ec8a
--- /dev/null
@@ -0,0 +1,60 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.SegmenterRegistry;
+import ie.dcu.apps.ist.views.SegmentationView;
+import ie.dcu.segment.Segmenter;
+
+/**
+ * Segmenter radio buttons.
+ * 
+ * @author Kevin McGuinness
+ */
+public class SelectSegmenterAction extends AppAction {
+       private final Segmenter segmenter;
+
+       public SelectSegmenterAction(ActionManager m, SegmenterRegistry r, Segmenter s) {
+               super(m, AS_RADIO_BUTTON);
+               this.segmenter = s;
+               setText(s.getName());
+               setToolTipText(s.getDescription());
+               
+               if (!s.isAvailable()) {
+                       super.setEnabled(false);
+                       setChecked(false);
+                       
+                       String naText = string("NA");
+                       setToolTipText(naText);
+                       setDescription(naText);
+               } else {
+                       setChecked(r.isDefault(s));
+               }
+       }
+       
+       public void setEnabled(boolean enabled) {
+               // Disallow enabling unavailable segmentation algorithms
+               if (!enabled || (segmenter.isAvailable() && enabled)) {
+                       super.setEnabled(enabled);
+               }
+       }
+       
+       
+       public Segmenter getSegmenter() {
+               return segmenter;
+       }
+
+       
+       @Override
+       public String id() {
+               return segmenter.getClass().getName();
+       }
+
+
+       @Override
+       public void run() {
+               if (isChecked()) {
+                       SegmentationView view = window.getView();
+                       view.setSegmenter(segmenter);           
+               }
+       }
+       
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/actions/UndoAction.java b/image_annotation/src/ie/dcu/apps/ist/actions/UndoAction.java
new file mode 100644 (file)
index 0000000..d5c67f2
--- /dev/null
@@ -0,0 +1,22 @@
+package ie.dcu.apps.ist.actions;
+
+import ie.dcu.apps.ist.views.SegmentationView;
+
+/**
+ * Undo last annotation.
+ *  
+ * @author Kevin McGuinness
+ */
+public class UndoAction extends AppAction {
+       public UndoAction(ActionManager m) {
+               super(m);
+       }
+
+       @Override 
+       public void run() { 
+               SegmentationView view = window.getView();
+               if (view.canUndo()) {
+                       view.undo();
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/controllers/AnnotationTool.java b/image_annotation/src/ie/dcu/apps/ist/controllers/AnnotationTool.java
new file mode 100644 (file)
index 0000000..eb89bb0
--- /dev/null
@@ -0,0 +1,314 @@
+package ie.dcu.apps.ist.controllers;
+
+
+
+import ie.dcu.segment.annotate.*;
+import ie.dcu.swt.*;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.Canvas;
+
+public class AnnotationTool extends MouseMotionAdapter {
+       private final AnnotationManager manager;        
+       private ImageControl view;
+       private Canvas canvas;
+       
+       private Annotation current;
+       private AnnotationType type;
+       private int lineWidth;
+       private Point last;
+       private boolean invert;
+
+       
+       public AnnotationTool(AnnotationManager manager) {
+               this (manager, null);
+       }
+       
+       /**
+        * 
+        * @param manager
+        * @param view
+        */
+       public AnnotationTool(AnnotationManager manager, ImageControl view) {
+               assert (manager != null);
+               
+               this.manager = manager;
+               this.current = null;
+               this.lineWidth = 1;
+               this.type = AnnotationType.Foreground;
+               
+               attach(view);
+       }
+
+
+       /**
+        * 
+        * @param view
+        */
+       public void attach(ImageControl view) {
+               detach();
+       
+               if (view != null) {
+                       this.view = view;
+                       canvas = view.getCanvas();
+                       canvas.addMouseListener(this);
+                       canvas.addMouseMoveListener(this);
+               }
+       }
+               
+
+
+       public void detach() {
+               if (view != null) {
+                       canvas.removeMouseListener(this);
+                       canvas.removeMouseMoveListener(this);
+                       view = null;
+                       canvas = null;
+                       current = null;
+               }
+       }
+       
+       
+       /**
+        * Returns the image control associated with the annotation tool.
+        */
+       public ImageControl getView() {
+               return view;
+       }
+       
+               
+       /**
+        * @return the line width
+        */
+       public int getLineWidth() {
+               return lineWidth;
+       }
+
+
+       /**
+        * @param width the line width to set
+        */
+       public void setLineWidth(int width) {
+               assert (width > 0);
+               this.lineWidth = width;
+       }
+
+
+       /**
+        * @return the annotation type
+        */
+       public AnnotationType getType() {
+               return type;
+       }
+
+       
+       /**
+        * @param type the annotation type to set
+        */
+       public void setType(AnnotationType type) {
+               assert (type != null);
+               this.type = type;
+       }
+       
+
+
+       public void begin(Point pt) {           
+                       
+               // Create a new annotation
+               current = new Annotation(getTypeForUse(), lineWidth, view.canvasToImage(pt));
+               
+               // Give immediate visual feedback
+               feedback(pt);
+               
+               // Set last
+               last = pt;
+       }
+       
+       
+       public void append(Point pt) {
+                       
+               // Update the annotation
+               current.add(view.canvasToImage(pt));
+               
+               // Give immediate visual feedback
+               feedback(last, pt);
+               
+               // Set last
+               last = pt;
+       }
+       
+       
+       public void commit(Point pt) {
+               // Clip points to image bounds
+               clip(last, pt);
+               
+               // Add point to annotation
+               current.add(view.canvasToImage(pt));
+                       
+               // Add annotation to annotation manager
+               manager.add(current);
+               
+               // Give immediate visual feedback
+               feedback(last, pt);
+                       
+               // Mark current annotation as null
+               current = null;
+       }
+       
+       
+       public void cancel() {
+               
+               // Repaint dirty area
+               view.repaint(current.getBounds());
+               
+               // Discard annotation
+               current = null;
+       }
+       
+       
+       
+       @Override
+       public void mouseDown(MouseEvent e) {
+               if (view == null || !view.isEnabled()) {
+                       current = null;
+                       return;
+               }
+                       
+               ObservableImage image = view.getImage();
+               if (image != null) {
+                       
+                       if (e.button == 1 || e.button == 3) {
+                               
+                               Point pt = new Point(e.x, e.y);
+                               
+                               if (view.imageContains(pt)) {
+                               
+                                       // Check for right mouse button or ctrl modifier
+                                       
+                                       if (e.button == 3 || (e.stateMask & SWT.CTRL) != 0) {
+                                               // Invert type
+                                               invert = true;
+                                       } else {
+                                               invert = false;
+                                       }
+                                       
+                                       if (current != null) {
+                                               // Cancel last action
+                                               cancel();
+                                       }
+                                       
+                                       begin(pt);
+                               }
+                       }
+               }
+               
+               return;
+       }
+
+       
+       @Override
+       public void mouseMove(MouseEvent e) {
+               if (view == null || !view.isEnabled()) {
+                       current = null;
+                       return;
+               }
+               
+               if (current != null) {
+                       Point pt = new Point(e.x, e.y);
+                       
+                       if (view.imageContains(pt)) {
+                               // Normal case: append
+                               append(pt);
+                               
+                       } else {
+                               // Line drawn outside image
+                               
+                               if (view.getImage() != null) {
+                                       
+                                       commit(pt);
+                               
+                               } else {
+                                       // No image: cancel
+                                       cancel();
+                               }
+                       } 
+               }
+               
+       }
+
+
+       @Override
+       public void mouseUp(MouseEvent e) {
+               if (view == null || !view.isEnabled()) {
+                       current = null;
+                       return;
+               }
+               
+               if (current != null) {
+                       Point pt = new Point(e.x, e.y);
+                       
+                       if (view.imageContains(pt)) {
+                               
+                               // Normal case: commit
+                               commit(pt);
+                       } else {
+                               
+                         // Line drawn outside image
+                               if (view.getImage() != null) {
+                                       
+                                       commit(pt);
+                               } else {
+                                       
+                                       // No image
+                                       cancel();
+                               }
+                       }
+               }
+       }
+
+
+       private void clip(Point p, Point q) {
+               SwtUtils.clip(view.getCanvasImageBounds(), p, q);
+       }
+       
+
+       private GC createFeedbackGC() {
+               GC gc = new GC(canvas);
+               gc.setAntialias(SWT.ON);
+               gc.setLineCap(SWT.CAP_ROUND);
+               gc.setLineJoin(SWT.JOIN_ROUND);
+               gc.setLineWidth((int) Math.floor(lineWidth * view.getZoom()));
+               gc.setForeground(getTypeForUse().getColor());
+               return gc;
+       }
+       
+       
+       private void feedback(Point p1) {
+               feedback(p1, new Point(p1.x+1, p1.y));
+       }
+       
+       
+       private void feedback(Point p1, Point p2) {
+               GC gc = createFeedbackGC();
+               gc.setClipping(getClip(p1, p2));
+               gc.drawLine(p1.x, p1.y, p2.x, p2.y);
+               gc.dispose();
+       }
+       
+       
+       private Rectangle getClip(Point p1, Point p2) {
+               int x1 = Math.min(p1.x, p2.x) - lineWidth;
+               int x2 = Math.max(p1.x, p2.x) + lineWidth;
+               int y1 = Math.min(p1.y, p2.y) - lineWidth;
+               int y2 = Math.max(p1.y, p2.y) + lineWidth;
+               Rectangle r = new Rectangle(x1, y1, x2 - x1, y2 - y1);
+               return  r.intersection(view.getCanvasImageBounds());
+       }
+
+       
+       private AnnotationType getTypeForUse() {
+               return (invert) ? type.invert() : type;
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/controllers/MouseMotionAdapter.java b/image_annotation/src/ie/dcu/apps/ist/controllers/MouseMotionAdapter.java
new file mode 100644 (file)
index 0000000..70a08e4
--- /dev/null
@@ -0,0 +1,26 @@
+package ie.dcu.apps.ist.controllers;
+
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.widgets.*;
+
+public class MouseMotionAdapter extends MouseAdapter implements MouseMoveListener {
+
+       public MouseMotionAdapter() {
+       }
+
+
+       public MouseMotionAdapter(Control control) {
+               add(control);
+       }
+
+
+       public void add(Control control) {
+               control.addMouseListener(this);
+               control.addMouseMoveListener(this);
+       }
+
+
+       public void mouseMove(MouseEvent e) {   
+       }
+
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/dialogs/ExportDialog.java b/image_annotation/src/ie/dcu/apps/ist/dialogs/ExportDialog.java
new file mode 100644 (file)
index 0000000..6807637
--- /dev/null
@@ -0,0 +1,368 @@
+package ie.dcu.apps.ist.dialogs;
+
+import ie.dcu.apps.ist.export.imagemap.AreaShape;
+import ie.dcu.apps.ist.export.imagemap.RolloverEffect;
+import ie.dcu.swt.SwtUtils;
+import ie.dcu.swt.layout.LayoutFactory;
+
+import java.io.File;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Dialog;
+import org.eclipse.swt.widgets.DirectoryDialog;
+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.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+public class ExportDialog extends Dialog {
+
+       public class Result {
+               public final File folder;
+               public final String html;
+               public final String image;
+               public final String link;
+               public final String description;
+               public final AreaShape shape;
+               public final RolloverEffect effect;
+               public final boolean open;
+               
+               Result() {
+                       folder = new File(folderText.getText().trim());
+                       html = htmlText.getText().trim();
+                       image = imageText.getText().trim();
+                       link = linkText.getText().trim();
+                       description = descriptionText.getText();
+                       shape = getShape();
+                       effect = getEffect();
+                       open = openButton.getSelection();
+               }
+       };
+       
+       // Result
+       private Result result;
+       
+       // Top level components
+       private Shell shell;
+       private Composite content;
+       private Composite widgets;
+       private Composite buttons;
+       
+       // Widgets
+       private Text folderText;
+       private Button browseButton;
+       private Text htmlText;
+       private Text imageText;
+       private Text linkText;
+       private Button effectCheck;
+       private Combo effectCombo;
+       private Button[] shapeRadios;
+       private Text descriptionText;
+       private Button openButton;
+       
+       // Dialog buttons
+       private Button cancelButton;
+       private Button exportButton;
+       
+       // Effects
+       private final String[] ROLLOVER_EFFECTS = {
+               "Outline Object", "Darken Background", "Highlight Object"
+       };
+       
+       // Shapes
+       private final String[] SHAPES = {
+               "Polygon", "Rectangle", "Circle"
+       };
+       
+       // Default title
+       private static final String TITLE = "Export HTML Image Map";
+
+       public ExportDialog(Shell shell) {
+               super(shell);
+               setText(TITLE);
+       }
+
+       public ExportDialog(Shell shell, int style) {
+               super(shell, style);
+               setText(TITLE);
+       }
+       
+       public Result open() {
+               Shell parent = getParent();
+               shell = new Shell(parent, SWT.DIALOG_TRIM | 
+                       SWT.APPLICATION_MODAL | SWT.SHEET);
+               shell.setText(getText());
+               shell.setLayout(new FillLayout());
+               
+               createUI();
+               
+               shell.pack();
+               
+               SwtUtils.center(parent, shell);
+               
+               shell.open();
+               Display display = parent.getDisplay();
+               while (!shell.isDisposed()) {
+                       if (!display.readAndDispatch()) display.sleep();
+               }
+
+               return result;
+       }
+
+       private void createUI() {
+               // Overall layout
+               content = new Composite(shell, 0);
+               content.setLayout(LayoutFactory.createGridLayout(0, 0, 1, false));
+               widgets = new Composite(content, 0);
+               widgets.setLayout(LayoutFactory.createGridLayout(10, 5, 3, false));
+               widgets.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               hline(content);
+               buttons = new Composite(content, 0);
+               buttons.setLayout(LayoutFactory.createGridLayout(10, 5, 3, false));
+               buttons.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               
+               // Form content
+               label(widgets, "Export folder:");
+               folderText = text(widgets, "");
+               browseButton = button(widgets, "Browse...");
+               label(widgets, "HTML file name:");
+               htmlText = text(widgets, "imagemap.html");
+               spacer(widgets);
+               label(widgets, "Image file name:");
+               imageText = text(widgets, "image.png");
+               spacer(widgets);
+               hline(widgets);
+               label(widgets, "Export shape:");
+               shapeRadios = radios(widgets, SHAPES);
+               // TODO: Enable when available
+               shapeRadios[2].setEnabled(false);
+               spacer(widgets);
+               label(widgets, "Object link:");
+               linkText = text(widgets, "http://");
+               spacer(widgets);
+               label(widgets, "Object description:");
+               descriptionText = text(widgets, "");
+               spacer(widgets);
+               effectCheck = checkbox(widgets, "Rollover effect:", true, 1);
+               effectCombo = combo(widgets, ROLLOVER_EFFECTS);
+               spacer(widgets);
+               hline(widgets);
+               openButton = checkbox(widgets, 
+                               "Open image map in browser after export completes", true, 3);
+               
+               // Button bar
+               expander(buttons);
+               cancelButton = new Button(buttons, SWT.PUSH);
+               cancelButton.setLayoutData(layout4());
+               cancelButton.setText("Cancel");
+               exportButton = new Button(buttons, SWT.PUSH);
+               exportButton.setLayoutData(layout4());
+               exportButton.setText("Export");
+               
+               // Set the default button
+               shell.setDefaultButton(exportButton);
+               
+               // Add listeners
+               addListeners();
+       }
+       
+       private void addListeners() {
+               
+               browseButton.addListener(SWT.Selection, new Listener() {
+                       public void handleEvent(Event e) {
+                               String dir = getDirectory();
+                               if (dir != null) {
+                                       folderText.setText(dir);
+                               }
+                       }
+               });
+               
+               cancelButton.addListener(SWT.Selection, new Listener() {
+                       public void handleEvent(Event e) {
+                               result = null;
+                               shell.dispose();
+                       }
+               });
+               
+               exportButton.addListener(SWT.Selection, new Listener() {
+                       public void handleEvent(Event e) {
+                               if (validate()) {
+                                       result = new Result();
+                                       shell.dispose();
+                               }
+                       }
+               });
+               
+               effectCheck.addListener(SWT.Selection, new Listener() {
+                       public void handleEvent(Event e) {
+                               effectCombo.setEnabled(effectCheck.getSelection());
+                       }
+               });
+       }
+       
+       private boolean validate() {
+               
+               File folder = new File(folderText.getText());
+               if (!folder.isDirectory()) {
+                       validationError("The export folder must be specified");
+                       folderText.setFocus();
+                       return false;
+               }
+               
+               String htmlFile = htmlText.getText().trim();
+               if (htmlFile.equals("")) {
+                       validationError("The HTML file name cannot be empty");
+                       htmlText.setFocus();
+                       return false;
+               }
+               
+               String imageFile = imageText.getText().trim();
+               if (imageFile.equals("")) {
+                       validationError("The image file name cannot be empty");
+                       imageText.setFocus();
+                       return false;
+               }
+               
+               return true;
+       }
+       
+       private void validationError(String message) {
+               MessageBox box = new MessageBox(shell, SWT.OK | SWT.ICON_INFORMATION);
+               box.setMessage(message);
+               box.setText("Invalid Input");
+               box.open();
+       }
+
+       private AreaShape getShape() {
+               for (Button bt : shapeRadios) {
+                       if (bt.getSelection()) {
+                               return AreaShape.valueOf(bt.getText());
+                       }
+               }
+               return null;
+       }
+       
+       private RolloverEffect getEffect() {
+               RolloverEffect effect = null;
+               if (effectCheck.getSelection()) {
+                       String text = effectCombo.getText();
+                       if (text.equals("Outline Object")) {
+                               effect = RolloverEffect.outlineObject();
+                       } else if (text.equals("Darken Background")) {
+                               effect = RolloverEffect.darkenBackground();
+                       } else if (text.equals("Highlight Object")) {
+                               effect = RolloverEffect.brightenForeground();
+                       }
+               } 
+               return effect;
+       }
+       
+       private String getDirectory() {
+               DirectoryDialog dialog = new DirectoryDialog(shell);
+               return dialog.open();
+       }
+
+       private Button[] radios(Composite parent, String ... items) {
+               Composite c = new Composite(parent, SWT.NONE);
+               c.setLayout(LayoutFactory.createGridLayout(5, 10, items.length, false));
+               c.setLayoutData(layout2());
+               
+               Button[] bts = new Button[items.length];
+               for (int i = 0; i < bts.length; i++) {
+                       bts[i] = new Button(c, SWT.RADIO);
+                       bts[i].setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+                       bts[i].setText(items[i]);
+                       bts[i].setSelection(i == 0);
+               }
+               
+               return bts;
+       }
+       
+       private Label hline(Composite parent) {
+               Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
+               GridData data = new GridData(SWT.FILL, SWT.CENTER, false, false);
+               data.horizontalSpan = 3;
+               data.heightHint = 10;
+               label.setLayoutData(data);
+               return label;
+       }
+       
+       private Label spacer(Composite parent) {
+               Label label = new Label(parent, SWT.NONE);
+               label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+               return label;
+       }
+       
+       private Label expander(Composite parent) {
+               Label label = new Label(parent, SWT.NONE);
+               label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               return label;
+       }
+       
+       private Combo combo(Composite parent, String ... items) {
+               Combo combo = new Combo(parent, SWT.READ_ONLY);
+               combo.setItems(items);
+               combo.setLayoutData(layout2());
+               if (items.length > 0) {
+                       combo.select(0);
+               }
+               return combo;
+       }
+       
+       private Button checkbox(Composite parent, String text, 
+                       boolean checked, int span) {
+               
+               Button bt = new Button(parent, SWT.CHECK);
+               bt.setText(text);
+               bt.setSelection(checked);
+               GridData data = layout1();
+               data.horizontalSpan = span;
+               bt.setLayoutData(data);
+               return bt;
+       }
+       
+       private Label label(Composite parent, String text) {
+               Label label = new Label(parent, SWT.NONE);
+               label.setText(text);
+               label.setLayoutData(layout1());
+               return label;
+       }
+       
+       private Text text(Composite parent, String value) {
+               Text text = new Text(parent, SWT.BORDER | SWT.SINGLE);
+               text.setText(value);
+               text.setLayoutData(layout2());
+               return text;
+       }
+       
+       private Button button(Composite parent, String text) {
+               Button bt = new Button(parent, SWT.PUSH);
+               bt.setText(text);
+               bt.setLayoutData(layout3());
+               return bt;
+       }
+       
+       private GridData layout1() {
+               return new GridData(SWT.LEFT, SWT.CENTER, false, false);
+       }
+       
+       private GridData layout2() {
+               return new GridData(SWT.FILL, SWT.CENTER, true, false);
+       }
+       
+       private GridData layout3() {
+               return new GridData(SWT.RIGHT, SWT.CENTER, false, false);
+       }
+       
+       private GridData layout4() {
+               return new GridData(SWT.RIGHT, SWT.BOTTOM, false, false);
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/dialogs/PrefsDialog.java b/image_annotation/src/ie/dcu/apps/ist/dialogs/PrefsDialog.java
new file mode 100644 (file)
index 0000000..9ea4eeb
--- /dev/null
@@ -0,0 +1,435 @@
+package ie.dcu.apps.ist.dialogs;
+
+import static ie.dcu.segment.annotate.AnnotationType.*;
+import ie.dcu.apps.ist.*;
+import ie.dcu.apps.ist.AppPrefs.Keys;
+import ie.dcu.apps.ist.widgets.ColorSelector;
+import ie.dcu.swt.SwtUtils;
+import ie.dcu.swt.layout.LayoutFactory;
+
+import java.util.*;
+
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+public class PrefsDialog {
+       private static final String APPLICATION = "application";
+       private static final String STATUS      = "status";
+       private static final String VIEW        = "view";
+       private static final String TITLE       = "title";
+       private static final String GENERAL     = "general";
+       private static final String CLOSE       = "close";
+       private static final String RESET       = "reset";
+       private static final String TEXT        = "text";
+       private static final String ICON        = "icon";
+       private static final String TTIP        = "ttip";
+       private static final String EXPERIMENT  = "experiment";
+       
+       private final AppWindow window;
+       private final AppPrefs prefs;
+       private final Shell shell;
+       private final Composite content;
+       private final TabFolder folder;
+       private final Composite buttonBar;
+       private final Composite generalTab;
+       private final Button resetButton;
+       private final Button closeButton;
+       private final HashMap<String, Object> controls;
+       
+       private transient GridData gd;
+       
+
+       public PrefsDialog(AppWindow window) {
+               this.window = window;
+               this.prefs = window.getPrefs();
+               this.shell = createShell();
+               this.content = createContent();
+               this.folder = createTabFolder();
+               this.buttonBar = createButtonBar();
+               this.generalTab = createTab(GENERAL);
+               this.resetButton = createResetButton();
+               this.closeButton = createCloseButton();
+               this.controls = new HashMap<String, Object>();
+               
+               createControls();
+               loadPreferences();
+               
+               SwtUtils.center(window.getShell(), shell);
+       }
+       
+
+       private void createControls() {
+               // Initialize general tab
+               createBanner(generalTab, APPLICATION);
+               
+               createLabel(generalTab, Keys.CONFIRM_EXIT);
+               createCheckBox(generalTab, Keys.CONFIRM_EXIT);
+               
+               createBanner(generalTab, STATUS);
+               
+               createLabel(generalTab, Keys.ENABLE_FEEDBACK);
+               createCheckBox(generalTab, Keys.ENABLE_FEEDBACK);
+               
+               createBanner(generalTab, VIEW);
+               
+               createLabel(generalTab, Keys.FOREGROUND_COLOR);
+               createColorSelector(generalTab, Keys.FOREGROUND_COLOR);
+               
+               createLabel(generalTab, Keys.BACKGROUND_COLOR);
+               createColorSelector(generalTab, Keys.BACKGROUND_COLOR);
+               
+               createBanner(generalTab, EXPERIMENT);
+               
+               createLabel(generalTab, Keys.EXPERIMENT_EMBEDDED);
+               createCheckBox(generalTab, Keys.EXPERIMENT_EMBEDDED);
+       }
+
+       
+       private void loadPreferences() {
+               
+               // Load confirm exit
+               loadBool(Keys.CONFIRM_EXIT, true);
+               
+               // Load enable feedback 
+               loadBool(Keys.ENABLE_FEEDBACK, true);
+               
+               // Load foreground color 
+               loadColor(Keys.FOREGROUND_COLOR, DEFAULT_FOREGROUND);
+               
+               // Load background color 
+               loadColor(Keys.BACKGROUND_COLOR, DEFAULT_BACKGROUND);
+               
+               // Load experiment embedded
+               loadBool(Keys.EXPERIMENT_EMBEDDED, false);
+       }
+       
+
+       private Shell createShell() {
+               Shell s = new Shell(window.getShell(), SWT.SHELL_TRIM | SWT.SHEET);
+               
+               // Add listener
+               s.addListener(SWT.Close, adapter);
+               
+               // Use a fill layout
+               s.setLayout(new FillLayout());
+               
+               // Set size and title
+               s.setSize(420, 450);
+               s.setText(property(TITLE, "Preferences"));
+               
+               return s;
+       }
+       
+       
+       private Composite createContent() {
+               
+               // Create content pane with grid layout
+               Composite c = new Composite(shell, 0);
+               c.setLayout(new GridLayout());
+               return c;
+       }
+       
+       
+       private TabFolder createTabFolder() {
+               // Create folder
+               TabFolder f = new TabFolder(content, SWT.TOP);
+               
+               // Layout folder
+               f.setLayoutData(LayoutFactory.createGridData());
+               
+               return f;
+       }
+       
+       
+       private Composite createButtonBar() {
+               // Create bar
+               Composite bar = new Composite(content, SWT.NONE);
+               
+               // Layout bar
+               bar.setLayout(LayoutFactory.createGridLayout(0, 0, 2, true));
+               bar.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
+               
+               return bar;
+       }
+       
+       
+       private Composite createTab(String name) {
+               // Create item
+               TabItem item = new TabItem(folder, SWT.NONE);
+               item.setText(property(name, "tab", name));
+               
+               // Create control
+               Composite control = new Composite(folder, SWT.NONE);
+               control.setLayout(LayoutFactory.createGridLayout(10, 5, 2, false));
+               
+               // Set control
+               item.setControl(control);
+               
+               // Return control (item can be ignored)
+               return control;
+       }
+       
+       
+       private Button createResetButton() {
+               // Create button
+               Button bt = createButton(buttonBar, RESET, SWT.PUSH);
+               
+               // Layout button
+               gd = new GridData(SWT.LEFT, SWT.BOTTOM, true, false);
+               gd.minimumWidth = 85;
+               bt.setLayoutData(gd);
+               
+               // Done
+               return bt;
+       }
+       
+       
+       private Button createCloseButton() {
+               // Create button
+               Button bt = createButton(buttonBar, CLOSE, SWT.PUSH);
+               
+               // Layout button
+               gd = new GridData(SWT.RIGHT, SWT.BOTTOM, true, false);
+               gd.minimumWidth = 85;
+               bt.setLayoutData(gd);
+               
+               // Done
+               return bt;
+       }
+       
+       
+       private Button createCheckBox(Composite tab, String key) {
+               Button bt = new Button(tab, SWT.CHECK);
+               
+               // Layout button
+               gd = new GridData(SWT.RIGHT, SWT.CENTER, false, false);
+               gd.horizontalIndent = 5;
+               bt.setLayoutData(gd);
+               
+               // Add listener
+               bt.addListener(SWT.Selection, adapter);
+               bt.setData(key);
+               
+               // Put into controls
+               controls.put(key, bt);
+               
+               // Done
+               return bt;
+       }
+       
+       
+       private ColorSelector createColorSelector(Composite tab, String key) {
+               ColorSelector cs = new ColorSelector(tab);
+               
+               // Layout button
+               gd = new GridData(SWT.RIGHT, SWT.CENTER, false, false);
+               gd.horizontalIndent = 10;
+               gd.minimumWidth = 80;
+               cs.setLayoutData(gd);
+               
+               // Add listener
+               cs.addListener(SWT.Selection, adapter);
+               cs.setData(key);
+               
+               // Put into controls
+               controls.put(key, cs);
+               
+               // Done
+               return cs;
+       }
+
+
+       private Label createBanner(Composite tab, String key) {
+               // Create label
+               Label lb = new Label(tab, SWT.NONE);
+               lb.setText(property(key, key));
+               lb.setFont(JFaceResources.getBannerFont());
+               
+               // Layout label
+               gd = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1);
+               gd.verticalIndent = 5;
+               lb.setLayoutData(gd);
+               
+               return lb;
+       }
+       
+       
+       private Label createLabel(Composite tab, String key) {
+               // Create label
+               Label lb = new Label(tab, SWT.NONE);
+               lb.setText(property(key, TEXT, key));
+               
+               // Layout label
+               gd = new GridData(SWT.LEFT, SWT.CENTER, true, false);
+               gd.horizontalIndent = 5;
+               lb.setLayoutData(gd);
+               
+               return lb;
+       }
+       
+       
+       private Button createButton(Composite parent, String key, int style) {
+               Button bt = new Button(parent, style);
+               
+               // Configure button
+               configure(bt, key);
+               
+               // Add listener
+               bt.addListener(SWT.Selection, adapter);
+               
+               // Done
+               return bt;
+       }       
+       
+       
+       protected void handleEvent(Event event) {
+               switch (event.type) {
+               case SWT.Close:
+                       handleClose(event);
+                       break;
+               case SWT.Selection:
+                       handleSelection(event);
+                       break;
+               }
+               
+       }
+       
+
+       private void handleClose(Event event) {
+               // Prevent the shell from disposing on close
+               event.doit = false;
+               close();
+       }
+       
+
+       private void handleSelection(Event event) {
+               if (event.widget == closeButton) {
+                       close();
+               } else if (event.widget == resetButton) {
+                       reset();
+               } else {
+                       Object data = event.widget.getData();
+                       if (data instanceof String) {
+                               handleSelection(event, (String) data);
+                       }
+               }
+               
+       }
+
+
+       private void handleSelection(Event event, String key) {
+               
+               if (key.equals(Keys.ENABLE_FEEDBACK)) {
+                       storeBool(key);
+               
+               } else if (key.equals(Keys.FOREGROUND_COLOR)) {
+
+                       storeColor(key);
+                       
+               } else if (key.equals(Keys.BACKGROUND_COLOR)) {
+                       
+                       storeColor(key);
+               
+               } else if (key.equals(Keys.EXPERIMENT_EMBEDDED)) {
+               
+                       storeBool(key);
+               
+               } else if (key.equals(Keys.CONFIRM_EXIT)) {
+                       
+                       storeBool(key);
+               }
+               
+       }
+       
+       
+       private void storeBool(String key) {
+               Boolean bool = control(Button.class, key).getSelection();
+               prefs.put(Boolean.class, key, bool);
+       }
+       
+
+       private void storeColor(String key) {
+               RGB color = control(ColorSelector.class, key).getColor();
+               if (color != null) {
+                       prefs.put(RGB.class, key, color);
+               }
+       }
+       
+       
+       private void loadBool(String key, boolean def) {
+               Boolean bool = prefs.get(Boolean.class, key, def);
+               control(Button.class, key).setSelection(bool);
+       }
+       
+       
+       private void loadColor(String key, RGB def) {
+               RGB color = prefs.get(RGB.class, key, def);
+               control(ColorSelector.class, key).setColor(color);
+       }
+       
+
+       public void reset() {
+               // Set defaults
+               prefs.clear();
+               
+               // Reload
+               loadPreferences();
+       }
+
+
+       public void close() {
+               shell.setVisible(false);
+       }
+       
+       
+       public void open() {
+               shell.setVisible(true);
+       }
+       
+       
+       private void configure(Button bt, String key) {
+               // Read properties
+               String text = property(key, TEXT, "");
+               String icon = property(key, ICON, null);
+               String ttip = property(key, TTIP, null);
+               
+               // Set values
+               bt.setText(text);
+               bt.setImage(image(icon));
+               bt.setToolTipText(ttip);
+               bt.setData(key);
+       }
+       
+       
+       private <T> T control(Class<T> clazz, String key) {
+               return clazz.cast(controls.get(key));
+       }
+       
+       
+       private String property(String key, String def) {
+               Properties p = window.getProperties();
+               return p.getProperty(String.format("PrefsDialog.%s", key), def);
+       }
+       
+       
+       private String property(String key, String type, String def) {
+               Properties p = window.getProperties();
+               String prop = String.format("PrefsDialog.%s.%s", key, type);
+               return p.getProperty(prop, def);
+       }
+       
+       
+       private Image image(String url) {
+               return (url != null) ? window.getIcon(url) :  null;
+       }
+       
+       
+       private final Listener adapter = new Listener() {
+               public void handleEvent(Event event) {
+                       PrefsDialog.this.handleEvent(event);
+               }               
+       };
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/event/ContextChangeListener.java b/image_annotation/src/ie/dcu/apps/ist/event/ContextChangeListener.java
new file mode 100644 (file)
index 0000000..8c617a0
--- /dev/null
@@ -0,0 +1,7 @@
+package ie.dcu.apps.ist.event;
+
+import java.util.*;
+
+public interface ContextChangeListener extends EventListener {
+       public void contextChanged(ContextChangedEvent evt);
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/event/ContextChangedEvent.java b/image_annotation/src/ie/dcu/apps/ist/event/ContextChangedEvent.java
new file mode 100644 (file)
index 0000000..638dad9
--- /dev/null
@@ -0,0 +1,24 @@
+package ie.dcu.apps.ist.event;
+
+
+import ie.dcu.segment.SegmentationContext;
+
+import java.util.*;
+
+
+public class ContextChangedEvent extends EventObject {
+       private static final long serialVersionUID = 1L;
+       
+       public final SegmentationContext oldContext;
+       public final SegmentationContext newContext;
+
+       public ContextChangedEvent(
+                       Object source, 
+                       SegmentationContext oldContext,
+                       SegmentationContext newContext
+       ) {
+               super(source);
+               this.oldContext = oldContext;
+               this.newContext = newContext;
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/event/StateEvent.java b/image_annotation/src/ie/dcu/apps/ist/event/StateEvent.java
new file mode 100644 (file)
index 0000000..38c5bbc
--- /dev/null
@@ -0,0 +1,11 @@
+package ie.dcu.apps.ist.event;
+
+import java.util.*;
+
+public class StateEvent extends EventObject {
+       private static final long serialVersionUID = 1L;
+
+       public StateEvent(Object source) {
+               super(source);
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/event/StateListener.java b/image_annotation/src/ie/dcu/apps/ist/event/StateListener.java
new file mode 100644 (file)
index 0000000..525f253
--- /dev/null
@@ -0,0 +1,13 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.event;
+
+import java.util.*;
+
+/**
+ * @author Kevin McGuinness
+ */
+public interface StateListener extends EventListener {
+       public void stateChanged(StateEvent evt);
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/event/TickerEvent.java b/image_annotation/src/ie/dcu/apps/ist/event/TickerEvent.java
new file mode 100644 (file)
index 0000000..ae6124f
--- /dev/null
@@ -0,0 +1,25 @@
+package ie.dcu.apps.ist.event;
+
+
+import ie.dcu.apps.ist.widgets.Ticker;
+
+import java.util.EventObject;
+
+public class TickerEvent extends EventObject {
+       private static final long serialVersionUID = 755693053854019177L;
+
+       private final long elapsed;
+
+       public TickerEvent(Ticker t, long elapsed) {
+               super(t);
+               this.elapsed = elapsed;
+       }
+       
+       public Ticker getTicker() {
+               return (Ticker) getSource();
+       }
+       
+       public long getElapsed() {
+               return elapsed;
+       }
+};
diff --git a/image_annotation/src/ie/dcu/apps/ist/event/TickerListener.java b/image_annotation/src/ie/dcu/apps/ist/event/TickerListener.java
new file mode 100644 (file)
index 0000000..26b6269
--- /dev/null
@@ -0,0 +1,7 @@
+package ie.dcu.apps.ist.event;
+
+import java.util.*;
+
+public interface TickerListener extends EventListener {
+       public void tick(TickerEvent evt);
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/event/TimeoutEvent.java b/image_annotation/src/ie/dcu/apps/ist/event/TimeoutEvent.java
new file mode 100644 (file)
index 0000000..70659c3
--- /dev/null
@@ -0,0 +1,24 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.event;
+
+
+import ie.dcu.apps.ist.widgets.SwtTimer;
+
+import java.util.EventObject;
+
+/**
+ * @author Kevin McGuinness
+ */
+public class TimeoutEvent extends EventObject {
+       private static final long serialVersionUID = 1L;
+
+       public TimeoutEvent(SwtTimer source) {
+               super(source);
+       }
+       
+       public SwtTimer getTimer() {
+               return (SwtTimer) getSource();
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/event/TimeoutListener.java b/image_annotation/src/ie/dcu/apps/ist/event/TimeoutListener.java
new file mode 100644 (file)
index 0000000..c682041
--- /dev/null
@@ -0,0 +1,13 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.event;
+
+import java.util.*;
+
+/**
+ * @author Kevin McGuinness
+ */
+public interface TimeoutListener extends EventListener {
+       public void timeoutOccured(TimeoutEvent evt);
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/exp/Experiment.java b/image_annotation/src/ie/dcu/apps/ist/exp/Experiment.java
new file mode 100644 (file)
index 0000000..ef52005
--- /dev/null
@@ -0,0 +1,348 @@
+package ie.dcu.apps.ist.exp;
+
+import ie.dcu.eval.Evaluator;
+import ie.dcu.apps.ist.*;
+import ie.dcu.segment.Segmenter;
+
+import java.io.*;
+import java.util.*;
+
+public class Experiment {
+       public static final int MAX_TASKS = 2500;
+       public static final int MAX_SEGMENTERS = 50;
+       public static final int MAX_EVALUATORS = 100;
+       
+       private String name;
+       private File dir;
+       private File outputFile;
+       private int time;
+       private List<Segmenter> segmenters;
+       private List<Evaluator> evaluators;
+       private List<Task> tasks;
+       private StorageSelection saveUserMasks;
+       private File saveUserMasksDir;
+       
+       Experiment() {
+               
+       }
+       
+       
+       public String getName() {
+               return name;
+       }
+       
+       
+       public File getDirectory() {
+               return dir;
+       }
+       
+       
+       public File getOutputFile() {
+               return outputFile;
+       }
+       
+       
+       public int getTime() {
+               return time;
+       }
+       
+       
+       public StorageSelection getStorageSelection() {
+               return saveUserMasks;
+       }
+       
+       
+       public File getStorageDirectory() {
+               return saveUserMasksDir;
+       }
+       
+       
+       public List<Segmenter> getSegmenters() {
+               return Collections.unmodifiableList(segmenters);
+       }
+       
+       
+       public List<Evaluator> getEvaluators() {
+               return Collections.unmodifiableList(evaluators);
+       }
+       
+       
+       public List<Task> getTasks() {
+               return Collections.unmodifiableList(tasks);
+       }
+       
+       
+       public boolean using(Segmenter segmenter) {
+               for (Segmenter s : segmenters) {
+                       if (s.equals(segmenter)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
+       
+       public void load(File file) throws IOException, FormatException {
+               InputStream in = null;
+               try {
+                       in = new FileInputStream(file);
+                       load(in);
+               } finally {
+                       if (in != null) {
+                               in.close();
+                       }
+               }
+       }
+       
+       
+       public void load(InputStream in) throws IOException, FormatException {
+               
+               // Create properties object
+               Properties props = new Properties();
+               props.load(in);
+               
+               // Load name
+               name = props.getProperty("name", "Experiment");
+               
+               // Load directory
+               dir = getDir(props, "dir");
+               
+               // Load output file
+               outputFile = getOutputFile(props);
+               
+               // Load task time
+               time = getTimeout(props, "time");
+               
+               // Get save user masks selection
+               saveUserMasks = getStorageSelection(props, "save-user-masks");
+               
+               // .. and directory
+               saveUserMasksDir = getUserMaskDir(props, "save-user-masks.dir");
+               
+               // Load segmenters
+               segmenters = new ArrayList<Segmenter>();
+               for (int i = 1; i <= MAX_SEGMENTERS; i++) {
+                       String key = "segmenters." + i;
+                       String val = props.getProperty(key);
+                       
+                       if (val == null) {
+                               break;
+                       }
+                       
+                       Segmenter segmenter = findSegmenter(val);
+                       if (segmenter != null) {
+                               segmenters.add(segmenter);
+                       } else {
+                               exception("Segmenter not found: <%s>", val);
+                       }
+               }
+               
+               // Load evaluators
+               evaluators = new ArrayList<Evaluator>();
+               for (int i = 1; i <= MAX_EVALUATORS; i++) {
+                       String key = "evaluators." + i;
+                       String val = props.getProperty(key);
+                       
+                       if (val == null) {
+                               break;
+                       }
+                       
+                       Evaluator evaluator = findEvaluator(val);
+                       if (evaluator != null) {
+                               evaluators.add(evaluator);
+                       } else {
+                               exception("Evaluator not found: <%s>", val);
+                       }
+               }
+               
+               // Load tasks
+               tasks = new ArrayList<Task>();
+               for (int i = 1; i <= MAX_TASKS; i++) {
+                       
+                       // Form keys
+                       String imkey   = String.format("task.%d.im", i);
+                       String gtkey   = String.format("task.%d.gt", i);
+                       String desckey = String.format("task.%d.description", i);
+                       
+                       // Check if we're done
+                       if (props.getProperty(imkey) == null) {
+                               break;
+                       }
+                       
+                       // Get image and ground truth file
+                       File im = getFile(props, imkey);
+                       File gt = getFile(props, gtkey);
+                       
+                       // Get description
+                       String desc = getDescription(props, desckey);
+                       
+                       // Add task
+                       tasks.add(new Task(im, gt, desc));
+               }
+       }
+       
+       
+       private static StorageSelection getStorageSelection(
+               Properties props, String key
+       ) {
+               String prop = props.getProperty(key);
+               if (prop != null) {
+                       StorageSelection selection = StorageSelection.parse(prop);
+                       if (selection != null) {
+                               return selection;
+                       }
+               }
+               return StorageSelection.None;
+       }
+       
+       
+       private File getUserMaskDir(Properties props, String key) 
+               throws FormatException {
+               
+               String fname = props.getProperty(key);
+               if (fname == null) {
+                       fname = "user";
+               }
+               
+               File file = new File(fname);
+               if (!file.isAbsolute()) {
+                       file = new File(dir, fname);
+               }
+               
+               
+               if (!file.exists()) {
+                       // Try and create it
+                       if (!file.mkdirs()) {
+                               String path = file.getAbsolutePath();
+                               exception("Couldn't create directory %s", path);
+                       } 
+               
+               }       else if (!file.isDirectory()) {
+                       String path = file.getAbsolutePath();
+                       exception("%s is not a directory", path);
+               }
+               
+               return file;
+       }
+
+
+       private static Segmenter findSegmenter(String name) {
+               return SegmenterRegistry.getInstance().find(name);
+       }
+       
+       
+       private static Evaluator findEvaluator(String name) {
+               return EvaluatorRegistry.getInstance().find(name);
+       }
+       
+       
+       private File getOutputFile(Properties props) {
+               String fname = props.getProperty("output", "output.txt");
+               File file = new File(fname);
+               if (file.isAbsolute()) {
+                       return file;
+               }
+               return new File(dir, fname);
+       }
+       
+       
+       
+       private static String getDescription(Properties props, String key) 
+               throws FormatException {
+               
+               String desc = props.getProperty(key);
+               if (desc == null) {
+                       exception("Expected description property for %s", key);
+               }
+               return desc;
+       }
+       
+       
+       private File getFile(Properties props, String key) 
+               throws FormatException {
+               
+               String fname = props.getProperty(key);
+               
+               if (fname == null) {
+                       exception("Expected file property for %s", key);
+               }
+               
+               File file = new File(fname);
+               if (file.isAbsolute()) {
+                       if (file.isFile()) {
+                               return file;
+                       }
+               }
+               
+               file = new File(dir, fname);
+               if (!file.isFile()) {
+                       exception("File not found %s", file.getAbsolutePath());
+               }
+               
+               return file;
+       }
+       
+       
+       private static File getDir(Properties props, String key) 
+               throws FormatException {
+               
+               String prop = props.getProperty(key);
+               if (prop == null) {
+                       exception("Required directory element not found: %a",key);
+               }
+               
+               File file = new File(prop);
+               if (!file.isDirectory()) {
+                       exception("%s is not a directory", prop);
+               }
+               
+               return file;
+       }
+       
+       
+       private static int getTimeout(Properties props, String key) 
+               throws FormatException {
+               
+               String prop = props.getProperty(key, "120");
+               try {
+                       return Integer.parseInt(prop);
+               } catch (NumberFormatException ex) {
+                       exception("%s is not an integer", key);
+               }
+               
+               return 0;
+       }
+       
+       
+       private static void exception(String format, Object ... args) 
+               throws FormatException 
+       {
+               throw new FormatException(String.format(format, args));
+       }
+       
+       
+       public String toString() {
+               StringBuilder sb = new StringBuilder();
+               
+               sb.append("name=<").append(name).append('>');
+               sb.append(" dir=<").append(dir.getAbsolutePath()).append('>');
+               sb.append(" output=<").append(outputFile.getAbsolutePath()).append('>');
+               sb.append(" time=<").append(time).append('>');
+               
+               // Evaluators
+               sb.append(" evaluators={ ");
+               for (Evaluator e : evaluators) {
+                       sb.append(e.getName()).append(' ');
+               }
+               sb.append('}');
+               
+               // Tasks
+               sb.append(" tasks={ ");
+               for (Task t : tasks) {
+                       sb.append(t).append(' ');
+               }
+               sb.append('}');
+               
+               return sb.toString();
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/exp/ExperimentFactory.java b/image_annotation/src/ie/dcu/apps/ist/exp/ExperimentFactory.java
new file mode 100644 (file)
index 0000000..802d14a
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.exp;
+
+import java.io.*;
+
+/**
+ * @author Kevin McGuinness
+ */
+public class ExperimentFactory {
+       private static ExperimentFactory instance;
+       
+       protected ExperimentFactory() {
+               
+       }
+       
+       public static ExperimentFactory getInstance() {
+               if (instance == null) {
+                       instance = new ExperimentFactory();
+               }
+               return instance;
+       }
+       
+       
+       public Experiment load(File file) 
+               throws IOException, FormatException {
+               
+               Experiment ex = new Experiment();
+               ex.load(file);
+               return ex;
+       }
+       
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/exp/ExperimentManager.java b/image_annotation/src/ie/dcu/apps/ist/exp/ExperimentManager.java
new file mode 100644 (file)
index 0000000..b03a6f7
--- /dev/null
@@ -0,0 +1,217 @@
+package ie.dcu.apps.ist.exp;
+
+import ie.dcu.eval.Evaluator;
+import ie.dcu.segment.SegmentationMask;
+import ie.dcu.segment.SegmentationContext;
+import ie.dcu.apps.ist.AppWindow;
+import ie.dcu.apps.ist.actions.*;
+
+import java.io.*;
+import java.util.List;
+
+public class ExperimentManager {
+       
+       private final AppWindow window;
+       
+       private Experiment experiment;
+       private SegmentationContext activeContext;
+       private SegmentationMask referenceMask;
+       private ExperimentResults results;
+       private List<Task> tasks;
+       private Task activeTask;
+       private int progress;
+       private boolean aborted;
+       
+       
+       public ExperimentManager(AppWindow window) {    
+               this.window = window;
+       }
+       
+       
+       public void beginExperiment(Experiment ex) throws IOException {
+               experiment = ex;
+               tasks = experiment.getTasks();
+               activeContext = null;
+               activeTask = null;
+               progress = 0;
+               results = new ExperimentResults(experiment.getOutputFile());
+               results.beginDocument();
+               results.beginExperiment(experiment);
+       }
+       
+       
+       public void endExperiment() throws IOException {
+               results.endExperiment();
+               results.flush();
+               results.close();
+       }
+       
+       
+       public void abortExperiment() {
+               results.endExperiment();
+               results.close();
+               aborted = true;
+       }
+       
+       
+       public void beginTask() throws IOException {
+               if (isComplete()) {
+                       throw new IllegalStateException();
+               }
+               
+               // Set active task
+               activeTask = tasks.get(progress);
+               
+               // Load context into main window
+               loadContext();
+
+               // Load reference mask
+               loadReferenceMask();
+               
+               // Write task header to results
+               results.beginTask(progress, activeTask);
+       }
+       
+       
+       public void endTask() throws IOException {
+               
+               try {
+                       // Save final mask
+                       StorageSelection ss = experiment.getStorageSelection();
+                       if (ss != StorageSelection.None) {
+                               store(String.format("task-%d-final.png", progress));
+                       }
+                       
+               } finally {
+                       
+                       activeTask = null;
+                       activeContext = null;
+                       progress++;
+                       results.endTask();
+                       results.flush();
+               }
+       }
+       
+       
+       public boolean isComplete() {
+               return tasks.size() == progress || aborted;
+       }
+       
+       
+       public Experiment getExperiment() {
+               return experiment;
+       }
+       
+       
+       public String getTaskDescription() {
+               return activeTask.getDescription();
+       }
+       
+       
+       public Task getActiveTask() {
+               return activeTask;
+       }
+       
+       
+       public int getTaskCount() {
+               return tasks.size();
+       }
+       
+       
+       public int getProgress() {
+               return progress;
+       }
+       
+       
+       public SegmentationContext getActiveContext() {
+               return activeContext;
+       }
+       
+       
+       public List<Evaluator> getEvaluators() {
+               return experiment.getEvaluators();
+       }
+       
+       
+       public File getImageFile() {
+               return activeTask.getImageFile();
+       }
+       
+       
+       public SegmentationMask getCurrentMask() {
+               return activeContext.getMask();
+       }
+       
+       
+       public SegmentationMask getReferenceMask() {
+               return referenceMask;
+       }
+       
+       
+       public void evaluate(int elapsed) {
+               
+               if (!getCurrentMask().isUnknown()) {
+                       SegmentationMask im = getCurrentMask();
+                       SegmentationMask gt = getReferenceMask();
+                       
+                       results.beginEvaluation(elapsed);
+                       
+                       for (Evaluator evaluator : experiment.getEvaluators()) {
+                               // Execute evaluator
+                               evaluator.run(im, gt);
+                               
+                               // Add results
+                               addResults(evaluator);
+                       }
+                       
+                       results.endEvaluation();
+               }
+       }
+       
+       
+       public void store(int elapsed) throws IOException {
+               // Save current mask
+               if (!getCurrentMask().isUnknown()) {
+                       // Only save non empty masks
+                       StorageSelection ss = experiment.getStorageSelection();
+                       if (ss == StorageSelection.All) {
+                               store(String.format("task-%d-time-%d.png", progress, elapsed));
+                       }
+               }
+       }
+       
+       
+       private void store(String name) throws IOException {
+               SegmentationMask im = getCurrentMask();
+               File dir = experiment.getStorageDirectory();
+               File file = new File(dir, name);
+               im.save(file);
+       }
+
+
+       private void addResults(Evaluator evaluator) {
+               String[] measures = evaluator.getMeasures();
+               for (String measure : measures) {
+                       double value = evaluator.getMeasure(measure);
+                       results.addMeasure(measure, value);
+               }
+       }
+
+
+       private void loadReferenceMask() throws IOException {
+               referenceMask = new SegmentationMask(activeContext.getBounds());
+               referenceMask.load(activeTask.getMaskFile());
+       }
+
+
+       private void loadContext() throws IOException {
+               ActionManager actions = window.getActions();
+               OpenAction action = actions.get(OpenAction.class);
+       
+               if (!action.open(getImageFile())) {
+                       throw new IOException("Unable to load image file");
+               }
+               
+               activeContext = window.getContext();
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/exp/ExperimentResults.java b/image_annotation/src/ie/dcu/apps/ist/exp/ExperimentResults.java
new file mode 100644 (file)
index 0000000..2f54026
--- /dev/null
@@ -0,0 +1,109 @@
+package ie.dcu.apps.ist.exp;
+
+import java.io.*;
+
+public class ExperimentResults {
+       private static final String XML_HEADER =
+               "<?xml version=\"1.0\" encoding=\"UTF-8\"?>%n%n";
+       
+       private static final String BEGIN_EXPERIMENT_TAG = 
+               "<experiment name=\"%s\" time=\"%d\" dir=\"%s\">%n";
+       
+       private static final String BEGIN_TASK_TAG = 
+               "  <task id=\"%d\" image=\"%s\" gt=\"%s\">%n";
+       
+       private static final String BEGIN_EVALUATION_TAG = 
+               "    <evaluation time=\"%d\">%n";
+       
+       private static final String MEASURE_TAG = 
+               "      <measure name=\"%s\" value=\"%.5f\" />%n";
+       
+       private static final String END_EVALUATION_TAG = 
+               "    </evaluation>%n";
+       
+       private static final String END_TASK_TAG = 
+               "  </task>%n";
+       
+       private static final String END_EXPERIMENT_TAG = 
+               "</experiment>%n";
+       
+       
+       private final PrintStream out;
+       
+       
+       
+       ExperimentResults(File file) throws FileNotFoundException {
+               this(new FileOutputStream(file));
+       }
+       
+       
+       ExperimentResults(OutputStream out)  {
+               this.out = new PrintStream(new BufferedOutputStream(out));
+       }
+       
+       
+       public void beginDocument() {
+               write(XML_HEADER);
+       }
+       
+       
+       public void beginExperiment(Experiment ex) {
+               String dir = ex.getDirectory().getAbsolutePath();
+               write(BEGIN_EXPERIMENT_TAG, ex.getName(), ex.getTime(), dir);
+       }
+       
+       
+       public void beginTask(int idx, Task task) {
+               String im = task.getImageFile().getName();
+               String gt = task.getMaskFile().getName();
+               write(BEGIN_TASK_TAG, idx, im, gt);
+       }
+       
+       
+       public void beginEvaluation(int time) {
+               write(BEGIN_EVALUATION_TAG, time);
+       }
+       
+       
+       public void endEvaluation() {
+               write(END_EVALUATION_TAG);
+       }
+       
+       
+       public void addMeasure(String name, double value) {
+               write(MEASURE_TAG, name, value);
+       }
+       
+       
+       public void endTask() {
+               write(END_TASK_TAG);
+       }
+       
+       
+       public void endExperiment() {
+               write(END_EXPERIMENT_TAG);
+       }
+       
+       
+       public void endDocument() throws IOException {
+               flush();
+       }
+       
+       
+       public void flush() throws IOException {
+               out.flush();
+               if (out.checkError()) {
+                       throw new IOException();
+               }
+       }
+       
+       
+       public void close() {
+               out.close();
+       }
+       
+       
+       private void write(String format, Object ... args) {
+               out.printf(format, args);
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/exp/FormatException.java b/image_annotation/src/ie/dcu/apps/ist/exp/FormatException.java
new file mode 100644 (file)
index 0000000..8553f0d
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.exp;
+
+/**
+ * @author Kevin McGuinness
+ */
+public class FormatException extends Exception {
+
+       /**
+        * 
+        */
+       private static final long serialVersionUID = 1L;
+
+
+       /**
+        * 
+        */
+       public FormatException() {
+       }
+
+
+       /**
+        * @param message
+        */
+       public FormatException(String message) {
+               super(message);
+       }
+
+
+       /**
+        * @param cause
+        */
+       public FormatException(Throwable cause) {
+               super(cause);
+       }
+
+
+       /**
+        * @param message
+        * @param cause
+        */
+       public FormatException(String message, Throwable cause) {
+               super(message, cause);
+       }
+
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/exp/StorageSelection.java b/image_annotation/src/ie/dcu/apps/ist/exp/StorageSelection.java
new file mode 100644 (file)
index 0000000..aeae41f
--- /dev/null
@@ -0,0 +1,22 @@
+package ie.dcu.apps.ist.exp;
+
+/**
+ * Selection of what points in time to output the masks that
+ * the user has obtained so far in their interactions.
+ * 
+ * @author Kevin McGuinness
+ */
+public enum StorageSelection {
+       All,
+       None,
+       Final;
+       
+       public static StorageSelection parse(String s) {
+               for (StorageSelection ss : values()) {
+                       if (ss.toString().equalsIgnoreCase(s)) {
+                               return ss;
+                       }
+               }
+               return null;
+       }
+};
diff --git a/image_annotation/src/ie/dcu/apps/ist/exp/Task.java b/image_annotation/src/ie/dcu/apps/ist/exp/Task.java
new file mode 100644 (file)
index 0000000..754d4ed
--- /dev/null
@@ -0,0 +1,39 @@
+package ie.dcu.apps.ist.exp;
+
+import java.io.*;
+
+public class Task {
+
+       private final File imageFile;
+       private final File maskFile;
+       private final String description;
+
+
+       Task(File imFile, File gtFile, String desc) {
+               imageFile = imFile;
+               maskFile = gtFile;
+               description = desc;
+       }
+
+
+       public File getImageFile() {
+               return imageFile;
+       }
+
+
+       public File getMaskFile() {
+               return maskFile;
+       }
+
+
+       public String getDescription() {
+               return description;
+       }
+       
+       
+       public String toString() {
+               String im = imageFile.getAbsolutePath();
+               String gt = maskFile.getAbsolutePath();
+               return String.format("[ im=<%s> gt=<%s> desc=<%s> ]", im, gt, description);
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/export/imagemap/AreaShape.java b/image_annotation/src/ie/dcu/apps/ist/export/imagemap/AreaShape.java
new file mode 100644 (file)
index 0000000..11fc339
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.export.imagemap;
+
+/**
+ * The shape of the area tag for a HTML image map. 
+ * 
+ * @see <a href="http://www.w3.org/TR/html401/sgml/dtd.html#Shape"/>HTML 4 DTD</a>
+ * 
+ * @author Kevin McGuinness
+ */
+public enum AreaShape {
+       Polygon("poly"),
+       Rectangle("rect"),
+       Circle("circle");
+       
+       private String text;
+       
+       private AreaShape(String text) {
+               this.text = text;
+       }
+       
+       /**
+        * Returns the HTML shape attribute value.
+        */
+       public String toString() {
+               return text;
+       }
+}
\ No newline at end of file
diff --git a/image_annotation/src/ie/dcu/apps/ist/export/imagemap/ExportException.java b/image_annotation/src/ie/dcu/apps/ist/export/imagemap/ExportException.java
new file mode 100644 (file)
index 0000000..51bf4c5
--- /dev/null
@@ -0,0 +1,25 @@
+package ie.dcu.apps.ist.export.imagemap;
+
+/**
+ * Exception thrown when there is a problem producing the export.
+ * 
+ * @author Kevin McGuinness
+ */
+public class ExportException extends Exception {
+       private static final long serialVersionUID = 1L;
+
+       public ExportException() {
+       }
+
+       public ExportException(String message) {
+               super(message);
+       }
+
+       public ExportException(Throwable cause) {
+               super(cause);
+       }
+
+       public ExportException(String message, Throwable cause) {
+               super(message, cause);
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/export/imagemap/Exporter.java b/image_annotation/src/ie/dcu/apps/ist/export/imagemap/Exporter.java
new file mode 100644 (file)
index 0000000..1ac92c8
--- /dev/null
@@ -0,0 +1,179 @@
+package ie.dcu.apps.ist.export.imagemap;
+
+import ie.dcu.image.ContourTracer;
+import ie.dcu.segment.SegmentationMask;
+import ie.dcu.util.FileUtils;
+
+import java.awt.Polygon;
+import java.awt.image.*;
+import java.io.*;
+import java.util.*;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Exports HTML image maps from a segmentation mask and an image.
+ * 
+ * @author Kevin McGuinness
+ */
+public class Exporter {
+       private final SegmentationMask mask;
+       private final BufferedImage image;
+       
+       private RolloverEffect effect;
+       private String htmlFile = "imagemap.html";
+       private String imageFile = "image.png";
+       private String imageName = "image";
+       private String objectDescription = "";
+       private String objectLink = "";
+       private AreaShape exportShape = AreaShape.Polygon;
+       
+       public Exporter(BufferedImage image, SegmentationMask mask) {
+               this.image = image;
+               this.mask = mask;
+       }
+       
+       public RolloverEffect getEffect() {
+               return effect;
+       }
+
+       public void setEffect(RolloverEffect effect) {
+               this.effect = effect;
+       }
+
+       public String getHtmlFile() {
+               return htmlFile;
+       }
+
+       public void setHtmlFile(String htmlFile) {
+               this.htmlFile = htmlFile;
+       }
+
+       public String getImageFile() {
+               return imageFile;
+       }
+
+       public void setImageFile(String imageFile) {
+               this.imageFile = imageFile;
+       }
+
+       public String getImageName() {
+               return imageName;
+       }
+
+       public void setImageName(String imageName) {
+               this.imageName = imageName;
+       }
+
+       public String getObjectDescription() {
+               return objectDescription;
+       }
+
+       public void setObjectDescription(String description) {
+               this.objectDescription = description;
+       }
+
+       public String getObjectLink() {
+               return objectLink;
+       }
+
+       public void setObjectLink(String link) {
+               this.objectLink = link;
+       }
+
+       public AreaShape getExportShape() {
+               return exportShape;
+       }
+
+       public void setExportShape(AreaShape shape) {
+               this.exportShape = shape;
+       }
+
+       public void export(File folder) throws IOException, ExportException {
+               ContourTracer tracer = new ContourTracer(mask, SegmentationMask.FOREGROUND);
+               List<Polygon> trace = tracer.trace();
+               
+               if (trace.size() == 0) {
+                       throw new ExportException("No objects found");
+               }
+               
+               List<String> preloads = getPreloads(trace);
+               
+               // Write image
+               ImageIO.write(image, "png", new File(folder, imageFile));
+               
+               if (effect != null) {
+                       int i = 1;
+                       
+                       // Generate effect images
+                       for (Polygon object : trace) {
+                               RenderedImage im = effect.createEffect(image, object);
+                               File output = new File(folder, preloads.get(i++));
+                               ImageIO.write(im, "png", output);
+                       }
+               }
+               
+               // Create image map
+               ImageMap map = new ImageMap();
+               map.setImageHref(imageFile);
+               map.setImageName(imageName);
+               
+               // Add javascript preloads
+               for (String str : preloads) {
+                       map.addPreload(str);
+               }
+               
+               // Add areas
+               int idx = 1;
+               for (Polygon polygon : trace) {
+                       MapArea area = new MapArea();
+                       switch (exportShape) {
+                       case Polygon:
+                               area.setPolygon(polygon);
+                               break;
+                       case Rectangle:
+                               area.setRect(polygon.getBounds());
+                               break;
+                       case Circle:
+                               // TODO: Implement circle!
+                               
+                       default:
+                               area.setPolygon(polygon);
+                               break;
+                       }
+                       
+                       area.setAlt(objectDescription);
+                       area.setHref(objectLink);
+                       
+                       if (effect != null) {
+                               
+                               
+                               area.addAttr("onmouseover", 
+                                       String.format("rollover(document.%s, image%s)", 
+                                                       imageName, idx++));
+                               area.addAttr("onmouseout", 
+                                               String.format("rollover(document.%s, image0)", imageName));
+                       }
+                       
+                       map.addArea(area);
+               }
+               
+               map.exportToFile(new File(folder, htmlFile));
+       }
+       
+       private List<String> getPreloads(List<Polygon> trace) {
+               List<String> preloads = new ArrayList<String>();
+               preloads.add(imageFile);
+               
+               if (effect != null) {
+                       
+                       String basename = FileUtils.removeExtension(imageFile);
+                       for (int i = 0; i < trace.size(); i++) {
+                               String filename = String.format("%s-%d.png", basename, i);
+                               preloads.add(filename);
+                       }
+               }
+               
+               return preloads;
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/export/imagemap/HtmlTag.java b/image_annotation/src/ie/dcu/apps/ist/export/imagemap/HtmlTag.java
new file mode 100644 (file)
index 0000000..7b0943e
--- /dev/null
@@ -0,0 +1,80 @@
+package ie.dcu.apps.ist.export.imagemap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class used to generate HTML tags.
+ * 
+ * @author Kevin McGuinness
+ */
+class HtmlTag {
+       final String name;
+       final Map<String, String> attrs;
+
+       HtmlTag(String name) {
+               this.name = name;
+               this.attrs = new HashMap<String, String>();
+       }
+       
+       HtmlTag attr(String name, String value) {
+               attrs.put(name, escape(value));
+               return this;
+       }
+       
+       private static String escape(String value) {
+               return value.replaceAll("\"", "\\\\\"");
+       }
+
+       static void indent(StringBuffer sb, int indent) {
+               for (int i = 0; i < indent; i++) {
+                       sb.append(' ');
+               }
+       }
+       
+       void open(StringBuffer sb, int indent) {
+               open(sb, indent, false);
+       }
+       
+       void open(StringBuffer sb, int indent, boolean empty) {
+               
+               // Indent 
+               indent(sb, indent);
+               
+               // Write start of tag
+               sb.append('<').append(name);
+               
+               // Write attributes
+               boolean first = true;
+               for (Map.Entry<String, String> entry : attrs.entrySet()) {
+                       
+                       if (!first) {
+                               sb.append('\n');
+                               indent(sb, indent + name.length() + 1);
+                       }
+                       
+                       sb.append(' ');
+                       sb.append(entry.getKey());
+                       sb.append('=');
+                       sb.append('"');
+                       sb.append(entry.getValue());
+                       sb.append('"');
+                       
+                       first = false;
+               }
+               
+               if (empty) {
+                       sb.append('/');
+               }
+               sb.append('>').append('\n');
+       }
+       
+       void close(StringBuffer sb, int indent) {
+               indent(sb, indent);
+               sb.append('<');
+               sb.append('/');
+               sb.append(name);
+               sb.append('>');
+               sb.append('\n');
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/export/imagemap/ImageMap.java b/image_annotation/src/ie/dcu/apps/ist/export/imagemap/ImageMap.java
new file mode 100644 (file)
index 0000000..4125ccf
--- /dev/null
@@ -0,0 +1,184 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.export.imagemap;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Exports HTML image maps
+ * 
+ * @author Kevin McGuinness
+ */
+public class ImageMap {
+       private static final String TEMPLATE_FILE = "template.html";
+       
+       private String pageTitle;
+       private String imageName;
+       private String imageHref;
+       private String imageAlt;
+       private String mapName;
+       private final List<MapArea> areas;
+       private final List<String> preloads;
+       
+       public ImageMap() {
+               // set defaults :
+               this.pageTitle = "Image Map";
+               this.imageName = "image";
+               this.imageHref = "";
+               this.imageAlt = "";
+               this.mapName = "imagemap";
+               this.areas = new LinkedList<MapArea>();
+               this.preloads = new LinkedList<String>();
+       }
+
+       public String getPageTitle() {
+               return pageTitle;
+       }
+
+       public void setPageTitle(String pageTitle) {
+               assert (pageTitle != null);
+               this.pageTitle = pageTitle;
+       }
+
+       public String getImageName() {
+               return imageName;
+       }
+
+       public void setImageName(String imageName) {
+               this.imageName = imageName;
+       }
+
+       public String getImageHref() {
+               return imageHref;
+       }
+
+       public void setImageHref(String imageHref) {
+               assert (imageHref != null);
+               this.imageHref = imageHref;
+       }
+
+       public String getImageAlt() {
+               return imageAlt;
+       }
+
+       public void setImageAlt(String imageAlt) {
+               assert (imageAlt != null);
+               this.imageAlt = imageAlt;
+       }
+
+       public String getMapName() {
+               return mapName;
+       }
+
+       public void setMapName(String mapName) {
+               assert (mapName != null);
+               this.mapName = mapName;
+       }
+
+       public void addArea(MapArea area) {
+               areas.add(area);
+       }
+       
+       public List<MapArea> areas() {
+               return areas;
+       }
+       
+       public void addPreload(String preload) {
+               this.preloads.add(preload);
+       }
+       
+       public List<String> preloads() {
+               return preloads;
+       }
+
+       public String export() {
+               String template = loadTemplate();
+               
+               // Create preloads buffer
+               StringBuffer preloads = new StringBuffer();
+               int idx = 0;
+               for (String s : preloads()) {
+                       HtmlTag.indent(preloads, 8);
+                       preloads.append("var image").append(idx);
+                       preloads.append(" = new Image()\n");
+                       HtmlTag.indent(preloads, 8);
+                       preloads.append("image").append(idx);
+                       preloads.append(".src = '").append(s).append("'\n");
+                       idx++;
+               }
+               
+               StringBuffer contents = new StringBuffer();
+               for (MapArea area : areas) {
+                       contents.append('\n');
+                       area.export(contents, 8);
+               }
+               
+               Map<String, String> subs = new HashMap<String, String>();
+               subs.put("image-name", imageName);
+               subs.put("page-title", pageTitle);
+               subs.put("image-href", imageHref);
+               subs.put("image-alt", imageAlt);
+               subs.put("map-name", mapName);
+               subs.put("contents", contents.toString());
+               subs.put("preloads", preloads.toString());
+               
+               return substitute(template, subs);
+       }
+       
+       public void exportToFile(File file) throws IOException {
+               FileWriter writer = new FileWriter(file);
+               try {
+                       writer.append(export());
+               } finally {
+                       writer.close();
+               }
+       }
+       
+       private String substitute(String template, Map<String, String> subs) {
+               // This could be more efficient..
+               String result = template;
+               for (String key : subs.keySet()) {
+                       String regex = String.format("\\$\\{%s\\}", key);
+                       result = result.replaceAll(regex, subs.get(key));
+               }
+               
+               return result;
+       }
+       
+       private String loadTemplate() {
+               BufferedReader reader = new BufferedReader(new InputStreamReader(
+                               getClass().getResourceAsStream(TEMPLATE_FILE)));
+               
+               StringBuffer buff = new StringBuffer();
+               
+               try {
+                       String line;
+                       while ((line = reader.readLine()) != null) {
+                               buff.append(line).append('\n');
+                       }
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               } finally {
+                       try {
+                               reader.close();
+                       } catch (IOException e) {
+                               // Ignore
+                       }
+               }
+               
+               return buff.toString();
+       }
+       
+       public String toString() {
+               return export();
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/export/imagemap/MapArea.java b/image_annotation/src/ie/dcu/apps/ist/export/imagemap/MapArea.java
new file mode 100644 (file)
index 0000000..2dc7003
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.export.imagemap;
+
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.net.*;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+public class MapArea {
+       
+       private String href;
+       private String alt;
+       private AreaShape shape;
+       private int[] coords;
+       private final Map<String, String> attrs;
+       
+       public MapArea() {
+               href = "";
+               alt = "";
+               shape = AreaShape.Polygon;
+               coords = new int[0];
+               attrs = new HashMap<String, String>();
+       }
+       
+       public void addAttr(String key, String value) {
+               attrs.put(key, value);
+       }
+
+       public String getHref() {
+               return href;
+       }
+
+       public void setHref(String href) {
+               this.href = href == null ? "" : href;
+       }
+
+       public String getAlt() {
+               return alt;
+       }
+
+       public void setAlt(String alt) {
+               this.alt = alt == null ? "" : alt;
+       }
+
+       public AreaShape getShape() {
+               return shape;
+       }
+
+       public void setShape(AreaShape shape) {
+               this.shape = shape == null ? AreaShape.Polygon : shape;
+       }
+
+       public int[] getCoords() {
+               return coords;
+       }
+
+       public void setCoords(int[] coords) {
+               this.coords = coords == null ? new int[0] : coords;
+       }
+
+       public void setRect(Rectangle rect) {
+               setShape(AreaShape.Rectangle);
+               int[] coords = {
+                               rect.x, 
+                               rect.y, 
+                               rect.x + rect.width, 
+                               rect.y + rect.height
+               };
+               setCoords(coords);
+       }
+       
+       public void setCircle(int x, int y, int r) {
+               setShape(AreaShape.Circle);
+               int[] coords = { x, y, r };
+               setCoords(coords);
+       }
+       
+       public void setPolygon(Polygon poly) {
+               setShape(AreaShape.Polygon);
+               int[] coords = new int[2*poly.npoints];
+               for (int i = 0, j = 0; i < poly.npoints; i++) {
+                       coords[j++] = poly.xpoints[i];
+                       coords[j++] = poly.ypoints[i];
+               }
+               setCoords(coords);
+       }
+       
+       public void export(StringBuffer sb, int indent) {
+               String encodedHREF = href;
+               if (href.length() != 0) {
+                       try {
+                               URI uri = new URI(href);
+                               URL url = uri.toURL();
+                               encodedHREF = url.toString();
+                       } catch (URISyntaxException e) {
+                               // Ignore exceptions, the href string will be used instead
+                       } catch (MalformedURLException e) {
+                               // Ignore exceptions, the href string will be used instead
+                       }
+               }
+               
+               HtmlTag tag = new HtmlTag("area");
+               tag
+                 .attr("href", encodedHREF)
+                 .attr("alt", alt)
+                 .attr("title", alt)
+                 .attr("shape", shape.toString())
+                 .attr("coords", getCoordsString());
+               
+               for (Entry<String, String> entry : attrs.entrySet()) {
+                       tag.attr(entry.getKey(), entry.getValue());
+               }
+               
+               tag.open(sb, indent, true);
+       }
+       
+       public String getCoordsString() {
+               StringBuffer sb = new StringBuffer();
+               boolean first = true;
+               for (int coord : coords) {
+                       if (!first) {
+                               sb.append(',');
+                       }
+                       sb.append(coord);
+                       first = false;
+               }
+               return sb.toString();
+       }
+}
\ No newline at end of file
diff --git a/image_annotation/src/ie/dcu/apps/ist/export/imagemap/RolloverEffect.java b/image_annotation/src/ie/dcu/apps/ist/export/imagemap/RolloverEffect.java
new file mode 100644 (file)
index 0000000..8e5ea2b
--- /dev/null
@@ -0,0 +1,191 @@
+package ie.dcu.apps.ist.export.imagemap;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Stroke;
+import java.awt.geom.Area;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+
+/**
+ * The roll-over effect for the image map.
+ * 
+ * @author Kevin McGuinness
+ */
+public abstract class RolloverEffect {
+       
+       public abstract RenderedImage createEffect(Image image, Polygon object);
+       
+       public static RolloverEffect darkenBackground(float alpha) {
+               return new DarkenBackground(alpha);
+       }
+       
+       public static RolloverEffect darkenBackground() {
+               return new DarkenBackground();
+       }
+       
+       public static RolloverEffect brightenForeground(float alpha) {
+               return new BrightenForeground(alpha);
+       }
+       
+       public static RolloverEffect brightenForeground() {
+               return new BrightenForeground();
+       }
+       
+       public static RolloverEffect outlineObject() {
+               return new OutlineObject();
+       }
+       
+       public static RolloverEffect outlineObject(Color color) {
+               return new OutlineObject(color);
+       }
+       
+       public static RolloverEffect outlineObject(Color color, Stroke stroke) {
+               return new OutlineObject(color, stroke);
+       }
+       
+       public static class DarkenBackground extends RolloverEffect {
+               
+               private float alpha = 0.5f;
+               
+               public DarkenBackground() {
+                       
+               }
+
+               public DarkenBackground(float alpha) {
+                       this.alpha = alpha;
+               }
+
+               public float getAlpha() {
+                       return alpha;
+               }
+
+               public void setAlpha(float alpha) {
+                       this.alpha = alpha;
+               }
+
+               @Override
+               public RenderedImage createEffect(Image image, Polygon object) {
+                       int width = image.getWidth(null);
+                       int height = image.getHeight(null);
+                       BufferedImage im = new BufferedImage(width, height, 
+                                       BufferedImage.TYPE_INT_ARGB);
+                       
+                       Area area = new Area(new Rectangle(0,0,width,height));
+                       area.subtract(new Area(object));
+                       
+                       Graphics g = im.getGraphics();
+                       if (g instanceof Graphics2D) {
+                               Graphics2D g2 = (Graphics2D) g;
+                               g2.drawImage(image, 0, 0, null);
+                               g2.setColor(new Color(0,0,0,alpha));
+                               g2.fill(area);
+                       }
+                       
+                       return im;
+               }
+       }
+       
+       public static class BrightenForeground extends RolloverEffect {
+               
+               private float alpha = 0.5f;
+               
+               public BrightenForeground() {
+                       
+               }
+
+               public BrightenForeground(float alpha) {
+                       this.alpha = alpha;
+               }
+
+               public float getAlpha() {
+                       return alpha;
+               }
+
+               public void setAlpha(float alpha) {
+                       this.alpha = alpha;
+               }
+
+               @Override
+               public RenderedImage createEffect(Image image, Polygon object) {
+                       int width = image.getWidth(null);
+                       int height = image.getHeight(null);
+                       BufferedImage im = new BufferedImage(width, height, 
+                                       BufferedImage.TYPE_INT_ARGB);
+                       
+                       Graphics g = im.getGraphics();
+                       if (g instanceof Graphics2D) {
+                               Graphics2D g2 = (Graphics2D) g;
+                               g2.drawImage(image, 0, 0, null);
+                               g2.setColor(new Color(1,1,1,alpha));
+                               g2.fill(object);
+                       }
+                       
+                       return im;
+               }
+       }
+       
+       public static class OutlineObject extends RolloverEffect {
+               
+               private Color color = Color.white;
+               private Stroke stroke = new BasicStroke(2.0f, 
+                               BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
+               
+               public OutlineObject() {
+                       
+               }
+
+               public OutlineObject(Color color) {
+                       this.color = color;
+               }
+               
+               public OutlineObject(Color color, Stroke stroke) {
+                       this.color = color;
+                       this.stroke = stroke;
+               }
+
+               public Color getColor() {
+                       return color;
+               }
+
+               public void setColor(Color color) {
+                       this.color = color;
+               }
+
+               public Stroke getStroke() {
+                       return stroke;
+               }
+
+               public void setStroke(Stroke stroke) {
+                       this.stroke = stroke;
+               }
+
+               @Override
+               public RenderedImage createEffect(Image image, Polygon object) {
+                       int width = image.getWidth(null);
+                       int height = image.getHeight(null);
+                       BufferedImage im = new BufferedImage(width, height, 
+                                       BufferedImage.TYPE_INT_ARGB);
+                       
+                       Graphics g = im.getGraphics();
+                       if (g instanceof Graphics2D) {
+                               Graphics2D g2 = (Graphics2D) g;
+                               g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
+                                               RenderingHints.VALUE_ANTIALIAS_ON);
+                               g2.drawImage(image, 0, 0, null);
+                               g2.setColor(color);
+                               g2.setStroke(stroke);
+                               g2.draw(object);
+                       }
+                       
+                       return im;
+               }
+       }
+}
+
diff --git a/image_annotation/src/ie/dcu/apps/ist/export/imagemap/template.html b/image_annotation/src/ie/dcu/apps/ist/export/imagemap/template.html
new file mode 100644 (file)
index 0000000..159d2a1
--- /dev/null
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+    <!-- Generated using the CDVP Interactive Segmentation Tool -->
+    <meta http-equiv="Content-type" 
+          content="text/html; charset=utf-8"/>
+    <meta name="Generator" 
+          content="Interactive Segmentation Tool"/>
+    
+    <title>${page-title}</title>
+    
+    <script type="text/javascript" language="javascript">
+               
+${preloads}
+               
+        function rollover(docElem, image) {
+            docElem.src = image.src
+            return true
+        }
+        
+    </script>
+  
+</head>
+<body>
+    <!-- Image -->
+    <img name="${image-name}"
+         src="${image-href}" 
+         usemap="#${map-name}" 
+         alt="${image-alt}"
+         title="${image-alt}"/>
+    
+    <!-- Image map -->
+    <map name="${map-name}" id="${map-name}">
+${contents}
+    </map>
+</body>
+</html>
\ No newline at end of file
diff --git a/image_annotation/src/ie/dcu/apps/ist/recent/RecentFiles.java b/image_annotation/src/ie/dcu/apps/ist/recent/RecentFiles.java
new file mode 100644 (file)
index 0000000..16ef717
--- /dev/null
@@ -0,0 +1,234 @@
+package ie.dcu.apps.ist.recent;
+
+import java.io.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * Class for managing a recent documents list.
+ * 
+ * @author Kevin McGuinness
+ */
+public class RecentFiles implements Iterable<File> {
+       public static final int DEFAULT_CAPACITY = 10;
+       
+       
+       private final LinkedList<File> history;
+       private final List<RecentFilesListener> listeners;
+       private final File store;
+       private int capacity;
+       
+       
+       public RecentFiles(File store) {
+               
+               // Check the store is ok
+               checkValid(store);
+               
+               // Construct
+               this.history = new LinkedList<File>();
+               this.listeners = new LinkedList<RecentFilesListener>();
+               this.store = store;
+               this.capacity = DEFAULT_CAPACITY;
+               
+               // Add a vm shutdown hook
+               addShutdownHook();
+       }
+       
+       
+       public void setCapacity(int capacity) {
+               
+               // Check positive
+               if (capacity < 0) {
+                       throw new IllegalArgumentException("capacity < 0");
+               }
+               
+               if (this.capacity != capacity) {
+                       this.capacity = capacity;
+               
+                       // Capacity may have reduced
+                       boolean reduced = history.size() > capacity;
+                       while (history.size() > capacity) {
+                               history.removeLast();
+                       }
+                       
+                       // Fire change
+                       if (reduced) {
+                               fireHistoryChanged();
+                       }
+               }
+       }
+       
+       
+       public int getCapacity() {
+               return capacity;
+       }
+       
+
+       public void add(File file) {
+               if (!history.contains(file)) {
+                       history.addFirst(file);
+                       
+                       // Check if we have exceeded capacity
+                       if (history.size() > capacity) {
+                               history.removeLast();
+                       }
+                       
+                       // Fire change
+                       fireHistoryChanged();
+               }
+       }
+       
+       
+       public void clear() {
+               if (!empty()) {
+                       history.clear();
+                       fireHistoryChanged();
+               }
+       }
+
+
+       public List<File> files() {
+               return Collections.unmodifiableList(history);
+       }
+
+
+       public Iterator<File> iterator() {
+               return files().iterator();
+       }
+
+
+       public boolean empty() {
+               return history.isEmpty();
+       }
+
+
+       public void load() throws IOException {
+               if (!store.exists()) {
+                       // Create an empty store
+                       store.createNewFile();
+               }
+               
+               BufferedReader in = null;
+               try {
+                       read(in = new BufferedReader(new FileReader(store)));
+               
+               } finally {
+                       in.close();
+               }
+       }
+
+
+       public void store() throws IOException {
+               PrintWriter out = null;
+               try {
+                       write(out = new PrintWriter(store));
+                       
+               } finally {
+                       out.close();
+               }
+       }
+
+
+       public void addListener(RecentFilesListener rfl) {
+               listeners.add(rfl);
+       }
+       
+       
+       public void removeListener(RecentFilesListener rfl) {
+               listeners.remove(rfl);
+       }
+       
+
+       protected static Logger getLogger() {
+               return Logger.getLogger(RecentFiles.class.getName());
+       }
+
+
+       private void shutdown() {
+               try {
+                       store();
+               } catch (IOException e) {
+                       getLogger().warning("Error writing recent documents to store: " + e);
+               }
+       }
+
+
+       private void fireHistoryChanged() {
+               RecentFilesEvent evt = null;
+               for (RecentFilesListener listener : listeners) {
+                       if (evt == null) {
+                               evt = new RecentFilesEvent(this);
+                               listener.historyChanged(evt);
+                       }
+               }
+       }
+
+
+       private void checkValid(File store) {
+               if (store == null) {
+                       throw new IllegalArgumentException("store cannot be null");
+               }
+               
+               if (store.isDirectory()) {
+                       throw new IllegalArgumentException("store cannot be a directory");
+               }
+               
+               if (store.isFile()) {
+                       if (!store.canWrite()) {
+                               throw new IllegalArgumentException("store not writable");
+                       }
+               }
+       }
+
+
+       private void addShutdownHook() {
+               Runtime.getRuntime().addShutdownHook(new Thread() {
+                       public void run() {
+                               shutdown();
+                       }
+               });
+       }
+
+
+       private void read(BufferedReader in) throws IOException {
+               
+               // Remember old history to check for changes
+               LinkedList<File> old = new LinkedList<File>(history);
+               
+               // Clear history if not empty
+               history.clear();
+               
+               // Read files (discarding no longer existent ones)
+               String line;
+               while ((line = in.readLine()) != null) {
+                       
+                       // Stop when full
+                       if (history.size() == capacity) {
+                               break;
+                       }
+                       
+                       File file = new File(line);
+                       if (file.exists()) {
+                               history.add(file);
+                       }
+               }
+               
+               // Fire change if a change occurred
+               if (!history.equals(old)) {
+                       fireHistoryChanged();
+               }
+       }
+
+
+       private void write(PrintWriter out) throws IOException {
+               for (File file : history) {
+                       String path = file.getAbsolutePath();
+                       out.println(path);
+               }
+               
+               // Check for errors
+               if (out.checkError()) {
+                       throw new IOException("Error writing to file");
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/recent/RecentFilesEvent.java b/image_annotation/src/ie/dcu/apps/ist/recent/RecentFilesEvent.java
new file mode 100644 (file)
index 0000000..8b0932e
--- /dev/null
@@ -0,0 +1,17 @@
+package ie.dcu.apps.ist.recent;
+
+import java.util.*;
+
+public class RecentFilesEvent extends EventObject {
+       private static final long serialVersionUID = 1L;
+
+       
+       public RecentFilesEvent(RecentFiles source) {
+               super(source);
+       }
+
+       
+       public RecentFiles getList() {
+               return (RecentFiles) source;
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/recent/RecentFilesListener.java b/image_annotation/src/ie/dcu/apps/ist/recent/RecentFilesListener.java
new file mode 100644 (file)
index 0000000..8d50258
--- /dev/null
@@ -0,0 +1,8 @@
+package ie.dcu.apps.ist.recent;
+
+import java.util.*;
+
+public interface RecentFilesListener extends EventListener {
+
+       public void historyChanged(RecentFilesEvent evt);
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/views/ExperimentPanel.java b/image_annotation/src/ie/dcu/apps/ist/views/ExperimentPanel.java
new file mode 100644 (file)
index 0000000..94dc2e3
--- /dev/null
@@ -0,0 +1,547 @@
+/**
+ * 
+ */
+package ie.dcu.apps.ist.views;
+
+import ie.dcu.apps.ist.AppWindow;
+import ie.dcu.apps.ist.event.*;
+import ie.dcu.apps.ist.exp.*;
+import ie.dcu.apps.ist.widgets.SwtTimer;
+import ie.dcu.segment.annotate.*;
+
+import java.io.IOException;
+import java.util.Properties;
+import java.util.logging.*;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * @author Kevin McGuinness
+ */
+public class ExperimentPanel extends Composite {
+       
+       // Some property keys
+       private static final String DESCRIPTION_TITLE 
+               = "description.title";
+       
+       private static final String TIMEOUT_MESSAGE 
+               = "timeout-message";
+       
+       private static final String EXPERIMENT_COMPLETE_MESSAGE 
+               = "experiment-complete-message";
+
+       // Type of button in use
+       private static enum ButtonType { Start, Finish };
+       
+       // App window and experiment
+       private final AppWindow window;
+       private final Experiment experiment;
+       private final Logger log;
+       
+       // Controls
+       private final Group group;
+       private final Button button;
+       private final SwtTimer timer;
+       private final Text text;
+       
+       // Shell if the panel is inside a shell
+       private Shell shell;
+       
+       // Experiment manager
+       private final ExperimentManager manager;
+       private final EvaluationListener evaluator;
+       
+       
+       public ExperimentPanel(AppWindow window, Composite parent, int style) {
+               super(parent, style);
+       
+               // Set app window
+               this.window = window;
+               this.experiment = window.getExperiment();
+               this.log = Logger.getLogger("Experiment");
+               
+               
+               // Create controls
+               timer  = new SwtTimer(this, SWT.NONE);
+               group = new Group(this, SWT.DEFAULT);
+               button = new Button(this, SWT.PUSH);
+               text   = new Text(group, SWT.READ_ONLY | SWT.WRAP); 
+               
+               // Create manager and evaluator
+               manager = new ExperimentManager(window);
+               evaluator = new EvaluationListener(manager, timer);
+               
+               // Setup controls
+               setupControls();
+               layoutControls();
+               addListeners();
+               
+               // Begin experiment
+               beginExperiment();
+       }
+       
+       
+       public static void open(AppWindow win) {
+               Shell app = win.getShell();
+               
+               // Style bits
+               int style = SWT.MODELESS | SWT.RESIZE | SWT.BORDER | SWT.TITLE | SWT.CLOSE;
+               
+               // Construct shell
+               Shell shell = new Shell(app, style);
+               
+               // Determine shell bounds
+               Rectangle bounds = new Rectangle(0,0,180,280);
+               
+               // Move shell to an appropriate place (right of app window)
+               Rectangle rect = app.getBounds();
+               bounds.x = rect.x + rect.width;
+               bounds.y = rect.y + rect.height / 2 - bounds.height / 2;
+               
+               // Move back if outside the screen
+               Rectangle screen = shell.getDisplay().getBounds();
+               if (bounds.x + bounds.width > screen.width) {
+                       bounds.x -= bounds.x + bounds.width - screen.width;
+               }
+
+               // Set bounds
+               shell.setBounds(bounds);
+       
+               // Set layout
+               shell.setLayout(new FillLayout());
+               
+               // Create experiment panel
+               final ExperimentPanel panel 
+                       = new ExperimentPanel(win, shell, SWT.NONE);
+               
+               panel.shell = shell;
+               panel.updateTitle();
+               
+               // Add shell close button listener
+               shell.addShellListener(new ShellAdapter() {
+                       public void shellClosed(ShellEvent e) {
+                               if (!panel.manager.isComplete()) {
+                                       e.doit = panel.cancelExperiment();
+                               }
+                       }
+               });
+               
+               // Open experiment panel
+               shell.open();
+       }
+
+       
+       private void setupControls() {
+               group.setText(property(DESCRIPTION_TITLE));
+               text.setEnabled(false);
+               enableButton(null);
+       }
+
+
+       private void layoutControls() {
+               GridLayout gl;
+               GridData   gd;
+               
+               // Setup layout manager for this
+               gl = new GridLayout();
+               gl.marginTop = 5;
+               gl.verticalSpacing = 5;
+               this.setLayout(gl);
+               
+               // Setup layout manager for group
+               gl = new GridLayout();
+               group.setLayout(gl);
+               
+               // Layout timer
+               gd = new GridData(SWT.FILL, SWT.FILL, true, false);
+               timer.setLayoutData(gd);
+               
+               // Layout group
+               gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+               group.setLayoutData(gd);
+               
+               // Layout button
+               gd = new GridData(SWT.FILL, SWT.FILL, true, false);
+               button.setLayoutData(gd);
+               
+               // Layout text
+               gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+               text.setLayoutData(gd);
+       }
+
+
+       private void addListeners() {
+               button.addListener(SWT.Selection, buttonListener);
+               timer.addTimeoutListener(timeListener);
+       }
+
+       
+       /**
+        * Function to call if something goes wrong with the experiment. Shows an
+        * error message and gracefully returns the application to normal mode.
+        * 
+        * @param reason
+        *          Short description of the problem.
+        */
+       private void abortExperiment(String reason) {
+               timer.clear();
+               evaluator.detach();
+               
+               // Show abort message
+               error("Aborting experiment!%n%s", reason);
+               
+               // Tell manager of abort
+               manager.abortExperiment();
+               
+               // Exit experiment mode
+               exitExperimentMode();
+       }
+       
+       
+       /**
+        * Does what is necessary to exit experiment mode.
+        */
+       private void exitExperimentMode() {
+               // Remove experiment view
+               window.setExperiment(null);
+               
+               // Re-enable interactions
+               window.getView().setEnabled(true);
+               
+               // Kill the shell
+               closeShell();
+       }
+       
+       
+       /**
+        * Closes the encompassing (non-application) shell, if any.
+        */
+       private void closeShell() {
+               if (shell != null) {
+                       shell.close();
+                       shell.dispose();
+                       shell = null;
+               }
+       }
+       
+       
+       private boolean cancelExperiment() {
+               // Make sure the user knows what they're doing
+               boolean cancel = MessageDialog.openQuestion(window.getShell(), "Confirm", 
+                               "Are you sure you want to cancel the experiment?");
+               
+               if (cancel) {
+                       // Guess we better do what the user says, grumble grumble :-/
+                       timer.clear();
+                       evaluator.detach();
+                       manager.abortExperiment();
+                       window.setExperiment(null);
+                       window.getView().setEnabled(true);
+               }
+               
+               return cancel;
+       }
+       
+       
+       /**
+        * Start the experiment.
+        */
+       private void beginExperiment() {
+               try {
+                       manager.beginExperiment(experiment);
+                       
+               } catch (IOException e) {
+                       log.log(Level.SEVERE, "Error starting experiment", e);
+                       abortExperiment(e.getMessage());
+               }
+               
+               // Begin first task
+               beginTask();
+       }
+       
+       
+       /**
+        * Finish the experiment.
+        */
+       private void endExperiment() {
+               try {
+                       manager.endExperiment();
+                       
+               } catch (IOException e) {
+                       log.log(Level.SEVERE, "Error ending experiment", e);
+                       abortExperiment(e.getMessage());
+               }
+               
+               // Tell user experiment is complete
+               notifyExperimentComplete();
+               
+               // Stop experiment mode
+               exitExperimentMode();
+       }
+       
+       
+       /**
+        * Load the task.
+        */
+       private void beginTask() {
+       
+               // Set timer
+               timer.set(experiment.getTime());
+               
+               // Begin task
+               try {
+                       manager.beginTask();
+               } catch (IOException e) {
+                       log.log(Level.SEVERE, "Error starting task", e);
+                       abortExperiment(e.getMessage());
+               }
+               
+               // Disable interactions
+               window.getView().setEnabled(false);
+               
+               // Update description
+               text.setText(manager.getTaskDescription());
+               
+               // Update title text
+               updateTitle();
+               
+               // Setup start button
+               enableButton(ButtonType.Start);
+               
+               // Attach evaluator
+               evaluator.attach();
+       }
+       
+       
+       private void updateTitle() {
+               if (shell != null) {
+                       int ntasks = manager.getTaskCount();
+                       int progress = manager.getProgress();
+                       shell.setText(String.format("Task [%d/%d]", progress+1, ntasks));
+               }
+       }
+
+
+       /**
+        * Start the task.
+        */
+       private void startTask() {
+               
+               // Enable interactions
+               window.getView().setEnabled(true);
+               
+               // Start clock
+               timer.start();
+               
+               // Enable finish button
+               enableButton(ButtonType.Finish);
+       }
+       
+
+       /**
+        * End the task.
+        */
+       private void endTask() {
+               // Detach evaluator
+               evaluator.detach();
+               
+               // Evaluate final result
+               manager.evaluate(timer.getElapsed());
+               
+               // End task
+               try {
+                       manager.endTask();
+               } catch (IOException e) {
+                       log.log(Level.SEVERE, "Error ending task", e);
+                       abortExperiment(e.getMessage());
+               }
+               
+               // Stop and clear clock
+               timer.clear();
+       }
+       
+       
+       /**
+        * End the current task and start the next. 
+        * End the experiment if finished.
+        */
+       private void nextTask() {
+               endTask();
+               if (manager.isComplete()) {
+                       endExperiment();
+               } else {
+                       beginTask();
+               }
+       }
+       
+
+       private void enableButton(ButtonType type) {
+               if (type != null) {
+                       String name = type.toString().toLowerCase();
+                       button.setText(property("button.text." + name));
+                       button.setData(type);
+                       button.setEnabled(true);
+                       button.setFocus();
+               } else {
+                       button.setText(property("button.text.start"));
+                       button.setEnabled(false);
+                       button.setData(null);
+               }
+       }
+       
+       
+       private ButtonType getEnabledButton() {
+               return (ButtonType) button.getData();
+       }
+
+
+       private void handleButtonClicked() {
+               ButtonType btn = getEnabledButton();
+               switch (btn) {
+               case Start:
+                       startTask();
+                       break;
+               case Finish:
+                       // Prevent clicking finish by accident
+                       if (manager.getActiveContext().getAnnotations().count() == 0) {
+                               getDisplay().beep();
+                       } else {
+                               nextTask();
+                       }
+                       break;
+               }
+       }
+
+
+       private void handleTimeout() {
+               // Finish task
+               endTask();
+               
+               // Tell user
+               notifyTimeoutOccurred();
+               
+               // Next task
+               if (manager.isComplete()) {
+                       endExperiment();
+               } else {
+                       beginTask();
+               }
+       }
+
+
+       private void notifyExperimentComplete() {
+               message(EXPERIMENT_COMPLETE_MESSAGE);
+       }
+
+
+       private void notifyTimeoutOccurred() {
+               // BEEP BEEP!! time up :-)
+               getDisplay().beep();
+               message(TIMEOUT_MESSAGE);
+       }
+
+
+       private void message(String key) {
+               Shell main = window.getShell();
+               MessageDialog.openInformation(main, "Information", property(key));
+       }
+       
+       
+       private void error(String message, Object ... args) {
+               Shell main = window.getShell();
+               MessageDialog.openError(main, "Error", String.format(message, args));
+       }
+
+
+       private String property(String key) {
+               return property(key, key);
+       }
+
+
+       private String property(String key, String def) {
+               Properties p = window.getProperties();
+               return p.getProperty(String.format("ExperimentPanel.%s", key), def);
+       }
+
+
+       private final Listener buttonListener = new Listener() {
+               public void handleEvent(Event event) {
+                       handleButtonClicked();
+               }
+       };      
+       
+       
+       private final TimeoutListener timeListener = new TimeoutListener() {
+               public void timeoutOccured(TimeoutEvent evt) {
+                       handleTimeout();
+               }
+       };
+}
+
+
+class EvaluationListener implements AnnotationListener {
+       private final ExperimentManager manager;
+       private final SwtTimer timer;
+       private final Logger log;
+       
+       public EvaluationListener(ExperimentManager manager, SwtTimer timer) {  
+               this.manager = manager;
+               this.timer = timer;
+               this.log = Logger.getLogger("Experiment");
+       }
+       
+       
+       public void attach() {
+               manager.getActiveContext().addAnnotationListener(this);
+       }
+       
+       
+       public void detach() {
+               manager.getActiveContext().removeAnnotationListener(this);
+       }
+       
+       
+       private void annotationsChanged(AnnotationEvent e) {
+               // Return if there is nothing to evaluate yet
+               if (e.manager.count() == 0) {
+                       return;
+               }
+                               
+               // Time the change occurred
+               int time = timer.getElapsed();
+               manager.evaluate(time);
+               
+               // Store if necessary
+               try {
+                       manager.store(time);
+               } catch (IOException ex) {
+                       log.log(Level.SEVERE, "Error storing intermediate segmentation mask", e);
+               }
+       }
+
+       
+       public void annotationPerformed(AnnotationEvent e) {
+               annotationsChanged(e);
+       }
+
+       
+       public void annotationRedone(AnnotationEvent e) {
+               annotationsChanged(e);
+       }
+
+       
+       public void annotationUndone(AnnotationEvent e) {
+               annotationsChanged(e);
+       }
+
+       
+       public void annotationsCleared(AnnotationEvent e) {
+               annotationsChanged(e);
+       }
+}
+
diff --git a/image_annotation/src/ie/dcu/apps/ist/views/SegmentationView.java b/image_annotation/src/ie/dcu/apps/ist/views/SegmentationView.java
new file mode 100644 (file)
index 0000000..14a1bef
--- /dev/null
@@ -0,0 +1,994 @@
+package ie.dcu.apps.ist.views;
+
+
+import ie.dcu.apps.ist.PainterRegistry;
+import ie.dcu.apps.ist.event.*;
+import ie.dcu.apps.ist.widgets.*;
+import ie.dcu.segment.*;
+import ie.dcu.segment.annotate.*;
+import ie.dcu.segment.options.SegmenterOptionDialog;
+import ie.dcu.segment.painters.SegmentationPainter;
+import ie.dcu.swt.*;
+import ie.dcu.swt.event.*;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.*;
+import java.util.Properties;
+import java.util.logging.*;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.*;
+import org.eclipse.jface.operation.*;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+public class SegmentationView extends Composite {
+       // Logger
+       private static final Logger log = Logger.getLogger(SegmentationView.class.getName());
+       
+       
+       // Segmentation view properties
+       private final Properties props;
+       
+       
+       // Houses various painters
+       private final PainterRegistry painters;
+       
+       
+       // View handling annotations
+       private final AnnotatedImageControl view;
+               
+       
+       // Left, center and right tool bar
+       private final ToolBar bar1, bar2, bar3;
+       
+       
+       // Control to change brush size
+       private final BrushControl brushControl;
+       
+       
+       // Handles various events
+       private final EventHandler eventHandler;
+       
+       
+       // Proxy object to catch and log exceptions thrown by the segmentation
+       // algorithm, without crashing the application.
+       private RobustSegmenterProxy segmenterProxy;
+       
+       
+       // Auto segment on update flag
+       private boolean auto = true;
+       
+       
+       // Combo box housing the selectable views
+       private Combo combo;
+       
+       
+       // Current segmentation tool
+       private Segmenter segmenter;
+       
+       
+       // Context to run the segmentation in, (may be null)
+       private IRunnableContext runnableContext;
+       
+       
+       // Flag to indicate that the runnable context blocks when fork is true
+       private boolean blocksOnFork;
+       
+       
+       public enum Tool {
+               Foreground,
+               Background,
+               ZoomIn,
+               ZoomOut,
+               ZoomOriginal,
+               ZoomBestFit,
+               Repaint,
+               Undo,
+               Redo,
+               Clear,
+               SetBrushSize,
+               AutoApply,
+               Apply,
+               SetPainter,
+               SetLabel,
+               SegmenterOptions;
+               private ToolAction action;
+       };
+       
+       
+       public SegmentationView(Properties props, Composite parent, int style) {
+               super(parent, style);
+               this.props = props;
+               
+               painters = new PainterRegistry();
+               bar1 = new ToolBar(this, SWT.LEFT | SWT.FLAT);
+               bar2 = new ToolBar(this, SWT.RIGHT | SWT.FLAT);
+               bar3 = new ToolBar(this, SWT.CENTER | SWT.FLAT);
+               view = new AnnotatedImageControl(this, SWT.BORDER);
+               brushControl = new BrushControl(getShell(), SWT.BORDER);
+               eventHandler = new EventHandler();
+               segmenterProxy = new RobustSegmenterProxy();
+               
+               init();
+       }
+
+
+       /**
+        * Initialize.
+        */
+       private void init() {
+               initTools();
+               createToolbar1();
+               createToolbar2();
+               createToolbar3();
+               layoutControls();
+               updatePainters();
+               addListeners();
+               updateToolStates();
+       }
+
+
+       private void initTools() {
+               for (Tool t : Tool.values()) {
+                       if (t.action == null) {
+                               new ToolAction(t);
+                       }
+               }
+       }
+
+
+       private void addListeners() {
+               brushControl.addSelectionListener(eventHandler);
+               view.addContextChangeListener(eventHandler);
+               view.addZoomListener(eventHandler);
+               addDisposeListener(eventHandler);
+       }
+
+
+       private void createToolbar1() {
+               ToolBarManager m = new ToolBarManager(bar1);
+               m.add(getAction(Tool.Foreground));
+               m.add(getAction(Tool.Background));
+               m.add(new Separator());
+               m.add(getAction(Tool.ZoomIn));
+               m.add(getAction(Tool.ZoomOut));
+               m.add(getAction(Tool.ZoomOriginal));
+               m.add(getAction(Tool.ZoomBestFit));
+               m.add(new Separator());
+               m.add(getAction(Tool.Repaint));
+               m.add(getAction(Tool.Undo));
+               m.add(getAction(Tool.Redo));
+               m.add(getAction(Tool.Clear));
+               m.add(new Separator());
+               m.add(getAction(Tool.SetBrushSize));
+               m.add(new Separator());
+               m.add(getAction(Tool.AutoApply));
+               m.add(getAction(Tool.Apply));
+               m.add(getAction(Tool.SegmenterOptions));
+               m.add(new Separator());
+               m.update(true);
+       }
+       
+       
+       private void createToolbar2() {
+               SwtUtils.addLabel(bar2, getAction(Tool.SetPainter).getText());
+               combo = SwtUtils.addCombo(bar2, 115, SWT.READ_ONLY);
+               combo.setToolTipText( getAction(Tool.SetPainter).getToolTipText());
+               combo.addSelectionListener(new SelectionAdapter() {
+                       public void widgetSelected(SelectionEvent e) {
+                               execute(Tool.SetPainter, null);
+                       }
+               });
+               bar2.pack();
+       }
+       
+       private void createToolbar3() {
+               SwtUtils.addLabel(bar3, getAction(Tool.SetLabel).getText());
+               ToolItem item = new ToolItem(bar3, SWT.SEPARATOR);
+               Text text = new Text(bar3, SWT.SINGLE);
+               text.setToolTipText( getAction(Tool.SetLabel).getToolTipText());
+               text.setText("Enter a Label");
+               item.setWidth(100);
+               item.setControl(text);
+               text.pack();
+               bar3.pack();
+               
+       }
+       
+       
+       private void layoutControls() {
+               GridLayout layout = new GridLayout(3, false);
+               layout.marginHeight = 1;
+               layout.marginWidth = 2;
+               layout.horizontalSpacing = -1; // zero leaves 1 pixel gap
+               layout.verticalSpacing = 1;
+               setLayout(layout);
+               
+               Point sz1 = bar1.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+               Point sz2 = bar2.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+               Point sz3 = bar3.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+               
+               int heightHintOfTwo = Math.max(sz1.y, sz2.y);
+               int heightHint = Math.max(heightHintOfTwo, sz3.y);
+               
+               // Layout toolbar 1
+               GridData gd = new GridData();
+               gd.grabExcessHorizontalSpace = true;
+               gd.horizontalAlignment = SWT.FILL;
+               gd.heightHint = heightHint;
+               bar1.setLayoutData(gd);
+               
+               // Layout toolbar 2
+               gd = new GridData();
+               gd.horizontalAlignment = SWT.FILL;
+               gd.heightHint = heightHint;
+               bar2.setLayoutData(gd);
+               
+               // Layout toolbar 3
+               gd = new GridData();
+               gd.horizontalAlignment = SWT.FILL;
+               gd.heightHint = heightHint;
+               bar3.setLayoutData(gd);
+               
+               // Layout view
+               gd = new GridData();
+               gd.verticalIndent = 3;
+               gd.horizontalSpan = 3;
+               gd.grabExcessHorizontalSpace = true;
+               gd.grabExcessVerticalSpace = true;
+               gd.horizontalAlignment = SWT.FILL;
+               gd.verticalAlignment = SWT.FILL;
+               view.setLayoutData(gd);
+       }
+       
+       
+       private void updatePainters() {
+               combo.removeAll();
+               boolean first = true;
+               for (SegmentationPainter p : painters.values()) {
+                       combo.add(p.getName());
+                       if (first) {
+                               combo.setText(p.getName());
+                               first = false;
+                       }
+               }
+       }
+       
+       
+       public void setSegmenter(Segmenter segmenter) {
+               if (this.segmenter != segmenter) {
+                       SegmentationContext ctx = view.getContext();
+                       
+                       if (this.segmenter != null && ctx != null) {
+                               // Finish old segmentation
+                               segmenterProxy.finish(ctx);
+                               
+                               // Remove old segmenter
+                               this.segmenter = null;
+                       }
+                       
+                       // Set new segmenter
+                       this.segmenter = segmenter;
+                       
+                       // Initialize a new segmentation
+                       start(ctx);
+                       
+                       // Update enabled buttons
+                       updateToolStates();
+               }
+       }
+       
+       
+       public Segmenter getSegmenter() {
+               return segmenter;
+       }
+       
+       
+       public void setContext(SegmentationContext ctx) {
+               
+               // context change handler handles initialization etc. 
+               // of segmenter and context
+               view.setContext(ctx);
+       }
+
+       
+       public SegmentationContext getContext() {
+               return view.getContext();
+       }
+       
+
+       public void setAnnotationType(AnnotationType type) {
+               view.setAnnotationType(type);
+       }
+       
+       
+       public Canvas getCanvas() {
+               return view.getCanvas();
+       }
+       
+       
+       public ImageControl getImageControl() {
+               return view.getImageControl();
+       }
+
+
+       public void zoomIn() {
+               view.zoomIn();
+       }
+
+
+       public void zoomOut() {
+               view.zoomOut();
+       }
+
+
+       public void zoomOriginal() {
+               view.zoomOriginal();
+       }
+
+
+       public void zoomBestFit() {
+               view.zoomBestFit();
+       }
+
+
+       public void repaint() {
+               view.repaint();
+       }
+
+
+       public void undo() {
+               view.undo();
+       }
+
+
+       public void redo() {
+               view.redo();
+       }
+
+
+       public void clear() {
+               view.clear();
+       }
+
+
+       public void setBrushSize(int size) {
+               view.setLineWidth(size);
+       }
+
+
+       // For labeling the image
+       public void setLabel(SegmentationPainter painter) {
+               view.setPainter(painter);
+               combo.setText(painter.getName());
+       }
+       
+       
+       public void setPainter(SegmentationPainter painter) {
+               view.setPainter(painter);
+               combo.setText(painter.getName());
+       }
+
+       
+       public SegmentationPainter getPainter() {
+               return view.getPainter();
+       }
+       
+
+       public void setAutoApply(boolean checked) {
+               if (!this.auto && checked) {
+                       // Going from off to on, resegment now
+                       apply();
+               }
+               this.auto = checked;
+       }
+       
+       
+       public boolean isAutoApply() {
+               return this.auto;
+       }
+
+
+       public boolean canZoomIn() {
+               return view.canZoomIn();
+       }
+
+
+       public boolean canZoomOut() {
+               return view.canZoomOut();
+       }
+
+
+       public boolean canZoomOriginal() {
+               return view.canZoomOriginal();
+       }
+
+
+       public boolean canZoomBestFit() {
+               return view.canZoomBestFit();
+       }
+
+
+       public boolean canUndo() {
+               return view.canUndo();
+       }
+
+
+       public boolean canRedo() {
+               return view.canRedo();
+       }
+
+
+       public boolean canClear() {
+               return view.canClear();
+       }
+       
+       
+       public boolean canShowOptions() {
+               if (hasSegmenter()) {
+                       return segmenter.getOptions().size() > 0;
+               }
+               return false;
+       }
+
+
+       public Action getAction(Tool t) {
+               return t.action;
+       }
+
+
+       public void showSegmenterOptions() {
+               if (canShowOptions()) {
+                       SegmenterOptionDialog dialog = 
+                               new SegmenterOptionDialog(getShell(), segmenter);
+               
+                       int result = dialog.open();
+                       switch (result) {
+                       case SegmenterOptionDialog.OK:
+                               // Re-segment
+                               apply();
+                       }
+               }
+       }
+       
+       
+       public boolean hasSegmenter() {
+               return segmenter != null;
+       }
+       
+
+       public void performSegmentation(AnnotationEvent e, SegmentationContext ctx) {
+               
+               if (runnableContext == null) {
+                       segment(e, ctx);
+               } else {
+                       segmentWithRunnableContext(e, ctx);
+               }
+               
+               // Repaint everything
+               repaint();
+               
+       }
+       
+       
+       public void setRunnableContext(IRunnableContext context, boolean blocksOnFork) {
+               runnableContext = context;
+               this.blocksOnFork = blocksOnFork;
+       }
+       
+       
+       public void addContextChangeListener(ContextChangeListener listener) {
+               view.addContextChangeListener(listener);
+       }
+       
+       
+       public void removeContextChangeListener(ContextChangeListener listener) {
+               view.removeContextChangeListener(listener);
+       }
+       
+       
+       public void setEnabled(boolean enabled) {
+               super.setEnabled(enabled);
+               bar1.setEnabled(enabled);
+               bar2.setEnabled(enabled);
+               view.setEnabled(enabled);
+               updateToolStates();
+       }
+       
+
+       private void run(boolean fork, IRunnableWithProgress runnable) {
+               boolean wasEnabled = isEnabled();
+               
+               try {
+                       // Disable interactions
+                       setEnabled(false);
+                       
+                       // Run segmentation
+                       runnableContext.run(fork, false, runnable);
+                       
+               } catch (InvocationTargetException ex) {
+                               
+                       // Can't happen without a runtime exception occurring, so re-wrap
+                       throw new RuntimeException(ex);
+                       
+               } catch (InterruptedException ex) {
+                       
+                       // Can't happen because cancellable is false
+                       throw new RuntimeException(ex);
+               
+               } finally {
+                       setEnabled(wasEnabled);
+               }
+       }
+
+
+       private void segmentWithRunnableContext(
+                       final AnnotationEvent e, 
+                       final SegmentationContext ctx) 
+       {
+               // Fork if the segmenter is slow, and only if our runnable context blocks 
+               boolean fork = blocksOnFork /*&& !segmenter.isFast()*/;
+               
+               run(fork, new IRunnableWithProgress() {
+                       public void run(IProgressMonitor monitor) {
+                               monitor.beginTask("Segmenting", IProgressMonitor.UNKNOWN);
+                               try {
+                                       segment(e, ctx);
+                               } finally {
+                                       monitor.done();
+                               }
+                       }
+               });
+       }
+
+       
+       private void start(final SegmentationContext ctx) {
+               if (ctx != null && hasSegmenter()) {
+                       if (runnableContext == null) {
+                               
+                               // No runnable context
+                               segmenterProxy.init(ctx);
+                               segmenterProxy.update(ctx);
+                                                               
+                       } else {
+                               
+                               // Run with progress monitor
+                               run(blocksOnFork, new IRunnableWithProgress() {
+                                       public void run(IProgressMonitor monitor) {
+                                               monitor.beginTask("Initializing", IProgressMonitor.UNKNOWN);
+                                               try {
+                                                       segmenterProxy.init(ctx);
+                                                       segmenterProxy.update(ctx);
+                                               } finally {
+                                                       monitor.done();
+                                               }
+                                       }
+                               });
+                               
+                       }
+                       
+                       // Repaint everything
+                       repaint();
+               }
+       }
+
+
+       private void segment(AnnotationEvent e, SegmentationContext ctx) {
+               if (hasSegmenter()) {
+                       if (e == null) {
+                               // No event triggered this, so do a full update
+                               segmenterProxy.update(ctx);
+                               
+                       } else {
+                               // Call appropriate segmenter function
+                               switch (e.type) {
+                               case Cleared:
+                                       segmenterProxy.update(ctx);
+                                       break;
+                                       
+                               case Undone:
+                                       segmenterProxy.removed(ctx, e.annotation);
+                                       break;
+                               
+                               case Redone:
+                               case Added:
+                                       segmenterProxy.added(ctx, e.annotation);
+                                       break;
+                               
+                               default:
+                                       throw new RuntimeException();
+                               }
+                       }
+               }
+       }
+
+
+       private boolean isAnnotatingBackground() {
+               return view.isAnnotatingBackground();
+       }
+       
+
+       private boolean isAnnotatingForeground() {
+               return view.isAnnotatingForeground();
+       }
+
+
+       private String getText(Tool a) {
+               return props.getProperty(getKey(a, "text"));
+       }
+
+
+       private String getToolTip(Tool a) {
+               return props.getProperty(getKey(a, "tooltip"));
+       }
+
+
+       private ImageDescriptor getImage(Tool a) {
+               String location = props.getProperty(getKey(a, "image"));
+               if (location != null) {
+                       if (location.length() == 0) {
+                               return null;
+                       }
+                       
+                       try {
+                               return ImageDescriptor.createFromURL(new URL(location));
+                       } catch (MalformedURLException e) {
+                               return null;
+                       }
+               }
+               
+               return null;
+       }
+
+
+       private static String getKey(Tool action, String object) {
+               return String.format("SegmentationView.Action.%s.%s", action, object);
+       }
+       
+       
+       private int getType(Tool a) {
+               switch (a) {
+               case Foreground:
+               case Background:
+               case AutoApply:
+                       return Action.AS_CHECK_BOX;
+               case SetBrushSize:
+                       return Action.AS_DROP_DOWN_MENU;
+               case SetPainter:
+                       return Action.AS_UNSPECIFIED;
+               default:
+                       return Action.AS_PUSH_BUTTON;
+               }
+       }
+       
+       
+       private void execute(Tool a, Event e) {
+               switch (a) {
+               case Foreground:
+                       setAnnotationType(AnnotationType.Foreground);
+                       break;
+               case Background:
+                       setAnnotationType(AnnotationType.Background);
+                       break;
+               case ZoomIn:
+                       zoomIn();
+                       break;
+               case ZoomOut:
+                       zoomOut();
+                       break;
+               case ZoomOriginal:
+                       zoomOriginal();
+                       break;
+               case ZoomBestFit:
+                       zoomBestFit();
+                       break;
+               case Repaint:
+                       repaint();
+                       break;
+               case Undo:
+                       undo();
+                       break;
+               case Redo:
+                       redo();
+                       break;
+               case Clear:
+                       clear();
+                       break;
+               case SetBrushSize:
+                       showBrushControl(e);
+                       break;
+               case AutoApply:
+                       setAutoApply(a.action.isChecked());
+                       break;
+               case Apply:
+                       apply();
+                       break;
+               case SetPainter:
+                       setPainter();
+                       break;
+               case SegmenterOptions:
+                       showSegmenterOptions();
+                       break;
+               }
+               
+               updateToolStates();
+       }
+       
+       
+       private void updateToolStates() {
+               if (isEnabled()) {
+                       Tool.Apply.action.setEnabled(!Tool.AutoApply.action.isChecked());
+                       Tool.Undo.action.setEnabled(canUndo());
+                       Tool.Redo.action.setEnabled(canRedo());
+                       Tool.ZoomIn.action.setEnabled(canZoomIn());
+                       Tool.ZoomOut.action.setEnabled(canZoomOut());
+                       Tool.ZoomOriginal.action.setEnabled(canZoomOriginal());
+                       Tool.ZoomBestFit.action.setEnabled(canZoomBestFit());
+                       Tool.Foreground.action.setChecked(isAnnotatingForeground());
+                       Tool.Background.action.setChecked(isAnnotatingBackground());
+                       Tool.Clear.action.setEnabled(canClear());
+                       Tool.AutoApply.action.setChecked(auto);
+                       Tool.SegmenterOptions.action.setEnabled(canShowOptions());
+                       
+                       // Always enabled if view enabled
+                       Tool.SetBrushSize.action.setEnabled(true);
+                       Tool.SegmenterOptions.action.setEnabled(true);
+                       Tool.SetPainter.action.setEnabled(true);
+                       Tool.Repaint.action.setEnabled(true);
+                       Tool.Foreground.action.setEnabled(true);
+                       Tool.Background.action.setEnabled(true);
+                       Tool.AutoApply.action.setEnabled(true);
+                       
+               } else {
+                       // Everything disabled
+                       for (Tool t : Tool.values()) {
+                               t.action.setEnabled(false);
+                       }
+               }
+               
+       }
+
+
+       private void setPainter() {
+               SegmentationPainter painter = painters.get(combo.getText());
+               setPainter(painter);
+       }
+
+
+       private void apply() {
+               performSegmentation(null, view.getContext());
+       }
+
+
+       private void showBrushControl(Event e) {
+               brushControl.showBelow(bar1, (ToolItem) e.widget);
+       }
+
+
+       /**
+        * Handles a context change in the view.
+        * 
+        * @param e
+        *          The event.
+        */
+       private void handleContextChanged(ContextChangedEvent e) {
+               if (e.oldContext != null) {
+                       e.oldContext.removeAnnotationListener(eventHandler);
+       
+                       // Finish old segmentation
+                       segmenterProxy.finish(e.oldContext);
+               }
+               
+               if (e.newContext != null) {
+                       e.newContext.addAnnotationListener(eventHandler);
+                       
+                       // Begin new segmentation (can cause deferred events
+                       // to be processed, so we async exec to ensure that
+                       // the other context change handlers are called before
+                       // deferred events are processed)
+                       final SegmentationContext ctx = e.newContext;
+                       getDisplay().asyncExec(new Runnable() {
+                               public void run() {
+                                       start(ctx);
+                               }
+                       });
+                       
+               }
+               
+               updateToolStates();
+       }
+
+
+       /**
+        * Cleans up resources when the view is disposed.
+        */
+       private void handleDisposed() {
+               
+               SegmentationContext ctx = view.getContext();
+               if (ctx != null && !ctx.isDisposed()) {
+                       
+                       // Finish any segmentation              
+                       segmenterProxy.finish(ctx);
+       
+                       // Dispose context
+                       ctx.dispose();
+               }
+               
+               // Dispose all painters
+               painters.dispose();
+       }
+
+
+       /**
+        * Tool bar action. Delegates running to the execute method.
+        */
+       private class ToolAction extends Action {
+               private final Tool tool;
+
+               public ToolAction(Tool tool) {
+                       super(SegmentationView.this.getText(tool), getType(tool));
+                       this.tool = tool;
+                       setToolTipText(SegmentationView.this.getToolTip(tool));
+                       setImageDescriptor(SegmentationView.this.getImage(tool));
+                       tool.action = this;
+               }
+               
+               public void runWithEvent(Event e) {
+                       execute(tool, e);
+               }
+       }
+       
+       
+       /**
+        * Handles various events coming from the view and toolbar controls.
+        * 
+        */
+       private final class EventHandler extends SelectionAdapter implements
+               ZoomListener, 
+               SelectionListener, 
+               ContextChangeListener, 
+               AnnotationListener,
+               DisposeListener
+       {
+               
+               public void widgetDisposed(DisposeEvent e) {
+                       handleDisposed();
+               }
+               
+
+               public void zoomChanged(ZoomEvent e) {
+                       updateToolStates();
+               }
+               
+
+               public void widgetSelected(SelectionEvent e) {
+                       setBrushSize(brushControl.getBrushSize());
+               }
+               
+
+               public void contextChanged(ContextChangedEvent e) {
+                       handleContextChanged(e);
+               }
+               
+
+               public void annotationPerformed(AnnotationEvent e) {
+                       if (!isEnabled()) {
+                               log.warning("annotation performed while not enabled");
+                       }
+                       
+                       if (auto && isEnabled()) {
+                               performSegmentation(e, view.getContext());
+                       }
+                       updateToolStates();
+               }
+
+               
+               public void annotationRedone(AnnotationEvent e) {
+                       if (!isEnabled()) {
+                               log.warning("annotation redone while not enabled");
+                       }
+                       
+                       if (auto && isEnabled()) {
+                               performSegmentation(e, view.getContext());
+                       }
+                       updateToolStates();
+               }
+
+               
+               public void annotationUndone(AnnotationEvent e) {
+                       if (!isEnabled()) {
+                               log.warning("annotation undone while not enabled");
+                       }
+                       
+                       if (auto && isEnabled()) {
+                               performSegmentation(e, view.getContext());
+                       }
+                       
+                       updateToolStates();
+               }
+
+               
+               public void annotationsCleared(AnnotationEvent e) {
+                       if (!isEnabled()) {
+                               log.warning("annotations cleared while not enabled");
+                       }
+                       
+                       if (auto && isEnabled()) {
+                               performSegmentation(e, view.getContext());
+                       }
+                       updateToolStates();
+               }
+       };
+       
+       /**
+        * Class that prevents segmentation algorithms crashing the application
+        * by catching any thrown exceptions and logging them.
+        * 
+        * @author Kevin McGuinness
+        */
+       private class RobustSegmenterProxy {
+
+               public void init(SegmentationContext ctx) {
+                       if (segmenter != null) {
+                               try {
+                                       segmenter.init(ctx);
+                               } catch (Throwable th) {
+                                       severe(th, "%s.init()", getSegmenterClassName());
+                               }
+                       }
+               }
+
+               public void update(SegmentationContext ctx) {
+                       if (segmenter != null) {
+                               try {
+                                       segmenter.update(ctx);
+                               } catch (Throwable th) {
+                                       severe(th, "%s.update()", getSegmenterClassName());
+                               }
+                       }
+               }
+
+               public void added(SegmentationContext ctx, Annotation a) {
+                       if (segmenter != null) {
+                               try {
+                                       segmenter.added(ctx, a);
+                               } catch (Throwable th) {
+                                       severe(th, "%s.added()", getSegmenterClassName());
+                               }
+                       }
+               }
+
+               public void removed(SegmentationContext ctx, Annotation a) {
+                       if (segmenter != null) {
+                               try {
+                                       segmenter.removed(ctx, a);
+                               } catch (Throwable th) {
+                                       severe(th, "%s.removed()", getSegmenterClassName());
+                               }
+                       }
+               }
+
+               public void finish(SegmentationContext ctx) {
+                       if (segmenter != null) {
+                               try {
+                                       segmenter.finish(ctx);
+                               } catch (Throwable th) {
+                                       severe(th, "%s.finish()", getSegmenterClassName());
+                               }
+                       }
+               }
+
+               public String getSegmenterClassName() {
+                       return segmenter.getClass().getSimpleName();
+               }
+               
+               private void severe(Throwable th, String message, Object ... args) {
+                       log.log(Level.SEVERE, String.format(message, args), th);
+               }
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/widgets/AnnotatedImageControl.java b/image_annotation/src/ie/dcu/apps/ist/widgets/AnnotatedImageControl.java
new file mode 100644 (file)
index 0000000..89eb761
--- /dev/null
@@ -0,0 +1,414 @@
+package ie.dcu.apps.ist.widgets;
+
+
+import ie.dcu.apps.ist.controllers.AnnotationTool;
+import ie.dcu.apps.ist.event.*;
+import ie.dcu.segment.SegmentationContext;
+import ie.dcu.segment.annotate.*;
+import ie.dcu.segment.painters.*;
+import ie.dcu.swt.*;
+import ie.dcu.swt.event.ZoomListener;
+
+import java.util.*;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.*;
+
+public class AnnotatedImageControl extends Composite {
+       private final List<ContextChangeListener> listeners;
+       private final ImageControl view;
+       private SegmentationContext ctx;
+       private AnnotationTool tool;
+       private SegmentationPainter painter;
+       private Cursor cursor;
+       
+       public AnnotatedImageControl(Composite parent, int style) {
+               super(parent, style);
+               setLayout(new FillLayout());
+               view = new ImageControl(this, SWT.NONE);
+               listeners = new ArrayList<ContextChangeListener>(2);
+               painter = new CombinedPainter();
+               view.getCanvas().addMouseMoveListener(cursorChanger);
+               addDisposeListener(disposeListener);
+       }
+       
+       
+       public ImageControl getImageControl() {
+               return view;
+       }
+       
+       
+       public Canvas getCanvas() {
+               return view.getCanvas();
+       }
+       
+       
+       public SegmentationPainter getPainter() {
+               return painter;
+       }
+       
+       
+       public void setPainter(SegmentationPainter painter) {
+               if (this.painter != painter) {
+                       this.painter = painter;
+                       recreate();
+               }
+       }
+       
+       
+       public SegmentationContext getContext() {
+               return ctx;
+       }
+       
+       
+       public void setContext(SegmentationContext ctx) {
+               
+               // Remember old context for event
+               SegmentationContext old = this.ctx;
+               
+               // Detach old tool
+               int lineWidth = 1;
+               if (tool != null) {
+                       lineWidth = tool.getLineWidth();
+                       tool.detach();
+                       tool = null;
+               }
+               
+               // Detach old annotation listener
+               if (ctx != null) {
+                       ctx.getAnnotations().removeAnnotationListener(listener);
+               }
+               
+               // Assign context
+               this.ctx = ctx;
+               
+               if (ctx != null) {
+                       // Attach new annotation listener
+                       AnnotationManager annotations = ctx.getAnnotations();
+                       annotations.addAnnotationListener(listener);
+                       
+                       // Attach a new annotation tool
+                       tool = new AnnotationTool(annotations, view);
+                       tool.setLineWidth(lineWidth);
+               }
+               
+               // Create the initial image
+               recreate();
+               
+               // Fire event
+               fireContextChanged(old);
+       }
+       
+
+       public int getLineWidth() {
+               if (tool != null) {
+                       return tool.getLineWidth();
+               }
+               return 1;
+       }
+       
+       
+       public void setLineWidth(int width) {
+               if (tool != null) {
+                       tool.setLineWidth(width);
+               }
+       }
+       
+       
+       public AnnotationType getAnnotationType() {
+               if (tool != null) {
+                       return tool.getType();
+               }
+               return AnnotationType.Foreground;
+       }
+       
+       
+       public void setAnnotationType(AnnotationType type) {
+               if (tool != null) {
+                       tool.setType(type);
+               }
+       }
+       
+       
+       public float getZoom() {
+               return view.getZoom();
+       }
+       
+       
+       public void setZoom(float zoom) {
+               view.setZoom(zoom);
+       }
+       
+       
+       public float getZoomStep() {
+               return view.getZoomStep();
+       }
+
+
+       public void setZoomStep(float zoomStep) {
+               view.setZoomStep(zoomStep);
+       }
+
+
+       public void zoomBestFit() {
+               view.zoomBestFit();
+       }
+
+
+       public void zoomIn() {
+               view.zoomIn();
+       }
+
+
+       public void zoomOriginal() {
+               view.zoomOriginal();
+       }
+
+
+       public void zoomOut() {
+               view.zoomOut();
+       }
+
+
+       public void undo() {
+               if (ctx != null) {
+                       ctx.getAnnotations().undo();
+               }
+       }
+       
+       
+       public void redo() {
+               if (ctx != null) {
+                       ctx.getAnnotations().redo();
+               }
+       }
+       
+       
+       public void clear() {
+               if (ctx != null) {
+                       ctx.getAnnotations().clear();
+               }
+       }
+       
+       
+       public boolean canUndo() {
+               if (ctx != null) {
+                       return ctx.getAnnotations().canUndo();
+               }
+               return false;
+       }
+       
+       
+       public boolean canRedo() {
+               if (ctx != null) {
+                       return ctx.getAnnotations().canRedo();
+               }
+               return false;
+       }
+       
+       
+       public boolean canClear() {
+               if (ctx != null) {
+                       return ctx.getAnnotations().count() > 0;
+               }
+               return false;
+       }
+       
+       
+       public boolean canZoomBestFit() {
+               return view.canZoomBestFit();
+       }
+
+
+       public boolean canZoomIn() {
+               return view.canZoomIn();
+       }
+
+
+       public boolean canZoomOriginal() {
+               return view.canZoomOriginal();
+       }
+
+
+       public boolean canZoomOut() {
+               return view.canZoomOut();
+       }
+       
+       
+       /**
+        * Redraw the entire canvas buffer.
+        */
+       public void repaint() {
+               if (ctx != null) {
+                       painter.paint(ctx, view.getImage());
+               }
+       }
+
+
+       public boolean isAnnotatingForeground() {
+               return getAnnotationType() == AnnotationType.Foreground;
+       }
+       
+       
+       public boolean isAnnotatingBackground() {
+               return getAnnotationType() == AnnotationType.Background;
+       }
+       
+       
+       public void addAnnotationListener(AnnotationListener listener) {
+               if (ctx == null) {
+                       throw new IllegalStateException();
+               }
+               ctx.getAnnotations().addAnnotationListener(listener);
+       }
+       
+
+       public void removeAnnotationListener(AnnotationListener listener) {
+               if (ctx != null) {
+                       ctx.getAnnotations().removeAnnotationListener(listener);
+               }
+       }
+       
+       
+       public void addZoomListener(ZoomListener listener) {
+               view.addZoomListener(listener);
+       }
+       
+       
+       public void removeZoomListener(ZoomListener listener) {
+               view.removeZoomListener(listener);
+       }
+       
+       
+       public void addContextChangeListener(ContextChangeListener listener) {
+               listeners.add(listener);
+       }
+       
+       
+       public void removeContextChangeListener(ContextChangeListener listener) {
+               listeners.remove(listener);
+       }
+       
+       
+       private void fireContextChanged(SegmentationContext old) {
+               ContextChangedEvent e = null;
+               for (ContextChangeListener l : listeners) {
+                       if (e == null) {
+                               e = new ContextChangedEvent(this, old, ctx);
+                       }
+                       l.contextChanged(e);
+               }
+       }
+       
+       
+       /**
+        * Re-construct the display image buffer, and dispose the old one if
+        * necessary. If the context is <code>null</code>, then set the display
+        * buffer to null and dispose of the old one.
+        */
+       private void recreate() {
+               if (ctx == null) {
+                       
+                       // Set null image (disposing the old one)
+                       view.setImage(null, true);
+                       
+               } else {
+                       
+                       // Check if we can reuse what we have
+                       boolean sameSize = false;
+                       if (view.hasImage()) {
+                               if (view.getImageBounds().equals(ctx.getBounds())) {
+                                       
+                                       // Okay, we can reuse the buffer we have :-)
+                                       sameSize = true;
+                               }
+                       }
+
+                       if (!sameSize) {
+               
+                               // Create initial image
+                               ObservableImage buffer = new ObservableImage(
+                                               SwtUtils.createImage(ctx.getBounds())
+                               );
+                               
+                               // Set the image (disposing the old one)
+                               view.setImage(buffer, true);
+                       }
+                       
+                       // Draw the image
+                       repaint();
+               }
+       }
+       
+       
+       private final DisposeListener disposeListener = new DisposeListener() {
+               public void widgetDisposed(DisposeEvent e) {
+                       if (cursor != null) {
+                               cursor.dispose();
+                       }
+               }
+       };
+
+       
+       /**
+        * Changes the cursor to a cross-hair when mouse is over the image.
+        * 
+        */
+       private final MouseMoveListener cursorChanger = new MouseMoveListener() {
+
+               public void mouseMove(MouseEvent e) {
+                       Canvas canvas = view.getCanvas();
+                       if (view.imageContains(new Point(e.x, e.y))) {
+                               if (cursor == null) {
+                                       cursor = CursorFactory.createCrosshairCursor();
+                               }
+                               canvas.setCursor(cursor);
+                       } else {
+                               canvas.setCursor(getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
+                       }
+               }
+       };
+
+
+       /**
+        * Listens for annotations and updates the buffer and view accordingly.
+        */
+       private final AnnotationListener listener = new AnnotationListener() {
+               
+               public void annotationUndone(AnnotationEvent e) {
+                       // Suspend notifications to prevent repainting the whole thing
+                       view.getImage().setSuspendNotifications(true);
+                       
+                       // Redraw all to buffer
+                       repaint();
+                       
+                       // Re-enable notifications
+                       view.getImage().setSuspendNotifications(false);
+                       
+                       // Repaint just the changed area
+                       view.getImage().fireImageChanged(e.annotation.getBounds());
+               }
+                       
+               
+               public void annotationsCleared(AnnotationEvent e) {
+                       // Repaint everything
+                       repaint();
+               }
+               
+               
+               public void annotationRedone(AnnotationEvent e) {       
+                       // Paint the new annotation
+                       e.annotation.paint(view.getImage());
+               }
+       
+               
+               public void annotationPerformed(AnnotationEvent e) {
+                       // Paint the new annotation
+                       e.annotation.paint(view.getImage());
+               }
+       };
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/widgets/BrushControl.java b/image_annotation/src/ie/dcu/apps/ist/widgets/BrushControl.java
new file mode 100644 (file)
index 0000000..9459f79
--- /dev/null
@@ -0,0 +1,101 @@
+package ie.dcu.apps.ist.widgets;
+
+import ie.dcu.swt.PopupComposite;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Pop up control for changing brush sizes.
+ * 
+ * @author Kevin McGuinness
+ */
+public class BrushControl extends PopupComposite {
+       private static final int MAX_BRUSH_SIZE = 20;
+
+       private final Label label;
+       private final Scale scale;
+       
+       
+       public BrushControl(Shell parent, int style) {
+               super(parent, style);
+               
+               // Create controls
+               label = new Label(this, SWT.NONE);
+               scale = new Scale(this, SWT.NONE);
+               
+               configureControls();
+               configureListeners();
+               layoutControls();
+       }
+
+
+       public void setBrushSize(int size) {
+               scale.setSelection(size);
+               updateLabel();
+       }
+       
+       
+       public int getBrushSize() {
+               return scale.getSelection();
+       }
+       
+       
+       public void addSelectionListener(SelectionListener listener) {
+               scale.addSelectionListener(listener);
+       }
+       
+       
+       public void removeSelectionListener(SelectionListener listener) {
+               scale.removeSelectionListener(listener);
+       }
+       
+       
+       private void configureControls() {
+               scale.setMinimum(1);
+               scale.setMaximum(MAX_BRUSH_SIZE);
+               scale.setIncrement(1);
+               scale.setPageIncrement(2);
+               setBrushSize(1);
+       }
+
+
+       private void configureListeners() {
+               scale.addSelectionListener(new ScaleChangeListener());
+       }
+
+
+       private void layoutControls() {
+               setLayout(new GridLayout());
+               
+               // Layout label
+               GridData gd = new GridData();
+               gd.grabExcessHorizontalSpace = true;
+               gd.horizontalAlignment = SWT.FILL;
+               label.setLayoutData(gd);
+               
+               // Layout scale control
+               gd = new GridData();
+               gd.grabExcessHorizontalSpace = true;
+               gd.horizontalAlignment = SWT.FILL;
+               gd.minimumWidth = 150;
+               scale.setLayoutData(gd);
+       }
+
+
+       private void updateLabel() {
+               int size = scale.getSelection();
+               label.setText(String.format("Brush Size:  %dpx ", size));
+       }
+
+
+       private final class ScaleChangeListener 
+               extends SelectionAdapter {
+               
+               public void widgetSelected(SelectionEvent e) {
+                       updateLabel();
+               }
+       };
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/widgets/ColorSelector.java b/image_annotation/src/ie/dcu/apps/ist/widgets/ColorSelector.java
new file mode 100644 (file)
index 0000000..7efcf9d
--- /dev/null
@@ -0,0 +1,175 @@
+package ie.dcu.apps.ist.widgets;
+
+import java.beans.*;
+
+import org.eclipse.jface.resource.*;
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Button for selecting colors.
+ * 
+ * @author Kevin McGuinness
+ */
+public class ColorSelector  {
+       public static final String DATA_KEY = "ColorEditor";
+       public static final String COLOR_PROPERTY = "color";
+
+       private final PropertyChangeSupport pcs;
+       private final Point extent;
+       private final Button button;
+       private final ControlListener listener;
+       
+       private Image image;
+       private RGB rgb;
+
+
+       public ColorSelector(Composite parent) {
+               
+               pcs = new PropertyChangeSupport(this);
+               button = new Button(parent, SWT.PUSH);
+               extent = computeImageSize(parent);
+               image = new Image(parent.getDisplay(), extent.x, extent.y);
+               listener = new ControlListener();
+
+               GC gc = new GC(image);
+               gc.setBackground(button.getBackground());
+               gc.fillRectangle(0, 0, extent.x, extent.y);
+               gc.dispose();
+
+               
+               button.setData(DATA_KEY, this);
+               button.setImage(image);
+               button.addListener(SWT.Selection, listener);
+               button.addListener(SWT.Dispose, listener);
+       }
+
+
+       public void addPropertyChangeListener(PropertyChangeListener listener) {
+               pcs.addPropertyChangeListener(listener);
+       }
+
+       
+       public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
+               pcs.addPropertyChangeListener(name, listener);
+       }
+
+
+       public PropertyChangeListener[] getPropertyChangeListeners() {
+               return pcs.getPropertyChangeListeners();
+       }
+
+       
+       public PropertyChangeListener[] getPropertyChangeListeners(String name) {
+               return pcs.getPropertyChangeListeners(name);
+       }
+
+       
+       public void removePropertyChangeListener(PropertyChangeListener listener) {
+               pcs.removePropertyChangeListener(listener);
+       }
+
+
+       public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
+               pcs.removePropertyChangeListener(name, listener);
+       }
+
+
+       public RGB getColor() {
+               return rgb;
+       }
+
+
+       public void setColor(RGB rgb) {
+               if (rgb != null && this.rgb != rgb) {
+                       RGB old = rgb;
+                       this.rgb = rgb;
+                       updateImage();
+                       pcs.firePropertyChange(COLOR_PROPERTY, old, rgb);
+               }
+       }
+       
+
+       public Button getButton() {
+               return button;
+       }
+
+
+       public void addListener(int eventType, Listener listener) {
+               button.addListener(eventType, listener);
+       }
+
+
+       public void setLayoutData(Object layoutData) {
+               button.setLayoutData(layoutData);
+       }
+       
+       
+       public void setData(Object data) {
+               button.setData(data);
+       }
+       
+       
+       public Object getData() {
+               return button.getData();
+       }
+
+
+       protected void updateImage() {
+               Display display = button.getDisplay();
+
+               GC gc = new GC(image);
+               gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
+               gc.drawRectangle(0, 2, extent.x - 1, extent.y - 4);
+
+               Color color = new Color(display, rgb);
+               gc.setBackground(color);
+               gc.fillRectangle(1, 3, extent.x - 2, extent.y - 5);
+               gc.dispose();
+
+               button.setImage(image);
+               color.dispose();
+       }
+
+
+       protected Point computeImageSize(Composite parent) {
+               GC gc = new GC(parent);
+               Font f = JFaceResources.getFontRegistry().get(JFaceResources.DEFAULT_FONT);
+               gc.setFont(f);
+               int height = gc.getFontMetrics().getHeight();
+               gc.dispose();
+               Point p = new Point(height * 3 - 6, height);
+               return p;
+       }
+       
+       
+       private void handleDispose(Event e) {
+               if (image != null) {
+                       image.dispose();
+                       image = null;
+               }
+       }
+       
+       
+       private void handleSelection(Event e) {
+               ColorDialog dialog = new ColorDialog(button.getShell());
+               dialog.setRGB(rgb);
+               RGB rgb = dialog.open();
+               setColor(rgb);
+       }
+       
+       
+       private final class ControlListener implements Listener {
+               public void handleEvent(Event e) {
+                       switch (e.type) {
+                       case SWT.Selection:
+                               handleSelection(e);
+                               break;
+                       case SWT.Dispose:
+                               handleDispose(e);
+                               break;
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/image_annotation/src/ie/dcu/apps/ist/widgets/ImageMenuManager.java b/image_annotation/src/ie/dcu/apps/ist/widgets/ImageMenuManager.java
new file mode 100644 (file)
index 0000000..cfe0050
--- /dev/null
@@ -0,0 +1,54 @@
+package ie.dcu.apps.ist.widgets;
+
+import java.net.URL;
+
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+
+public class ImageMenuManager extends MenuManager {
+       private Image image;
+       
+       public ImageMenuManager() {
+               super();
+       }
+
+       public ImageMenuManager(String text) {
+               super(text);
+       }
+       
+       public ImageMenuManager(String text, URL imageURL) {
+               super(text);
+               setImageURL(imageURL);
+       }
+       
+       public void setImageURL(URL url) {
+               ImageDescriptor descriptor = ImageDescriptor.createFromURL(url);
+               this.image = descriptor.createImage();
+       }
+       
+       @Override
+       public void dispose() {
+               super.dispose();
+               
+               if (image != null) {
+                       image.dispose();
+               }
+       }       
+       
+       @Override
+       public void fill(Menu parent, int index) {
+               super.fill(parent, index);
+               MenuItem item = getMenuItem();
+               if (item != null) {
+                       item.setImage(image);
+               }
+       }
+
+       protected MenuItem getMenuItem() {
+               Menu menu = getMenu();
+               return (menu != null) ? menu.getParentItem() : null;
+       }
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/widgets/SwtTimer.java b/image_annotation/src/ie/dcu/apps/ist/widgets/SwtTimer.java
new file mode 100644 (file)
index 0000000..6d1f97c
--- /dev/null
@@ -0,0 +1,642 @@
+package ie.dcu.apps.ist.widgets;
+
+
+import ie.dcu.apps.ist.event.*;
+
+import java.util.ArrayList;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * A timer user interface element. Displays a component used
+ * to implement a count-down.
+ * 
+ * @author Kevin McGuinness
+ */
+public class SwtTimer implements TickerListener {
+       
+       /**
+        * Timer is modeled as a state machine. These are the states.
+        */
+       public static enum State {      Initial, Ready, Running, Paused };
+       
+       
+       /**
+        * List of listeners interested in changes to the object state.
+        */
+       private final ArrayList<StateListener> stateListeners;
+       
+       
+       /**
+        * List of listeners interested in timeouts.
+        */
+       private final ArrayList<TimeoutListener> timeoutListeners;
+       
+       
+       /**
+        * The drawing canvas where the numbers are drawn.
+        */
+       private final Canvas canvas;
+       
+       
+       /**
+        * The ticker posts tick events every second or so.
+        */
+       private Ticker ticker;
+       
+       
+       /**
+        * The current state of the timer.
+        */
+       private State state;
+       
+       
+       /**
+        * The font used to render the numbers.
+        */
+       private Font font;
+       
+       
+       /**
+        * Total time for the timer, in seconds.
+        */
+       private int time;
+       
+       
+       /**
+        * Remaining (displayed) time, in seconds. 
+        */
+       private int remaining;
+       
+       
+       /**
+        * Create the timer. Style bits are passed to the underlying canvas.
+        * 
+        * @param parent
+        *          Parent container.
+        * @param style
+        *          Style bits.
+        */
+       public SwtTimer(Composite parent, int style) {
+               stateListeners = new ArrayList<StateListener>(1);
+               timeoutListeners = new ArrayList<TimeoutListener>(1);
+               canvas = new Canvas(parent, style);
+               addListeners();
+               enter(State.Initial);
+       }
+       
+       
+       /**
+        * Add listeners to various components.
+        */
+       private void addListeners() {
+               // Listen for paint events
+               canvas.addPaintListener(new PaintListener() {
+                       public void paintControl(PaintEvent e) {
+                               paint(e.gc);
+                       }
+               });
+               
+               // Listen for dispose event
+               canvas.addDisposeListener(new DisposeListener() {
+                       public void widgetDisposed(DisposeEvent e) {
+                               dispose();              
+                       }
+               });
+       }
+       
+       
+       /**
+        * Set the layout data for the component.
+        * 
+        * @param data
+        *          The layout data.
+        */
+       public void setLayoutData(Object data) {
+               canvas.setLayoutData(data);
+       }
+       
+       
+       /**
+        * Returns the layout data for the component.
+        * 
+        * @return The layout data.
+        */
+       public Object getLayoutData() {
+               return canvas.getLayoutData();
+       }
+       
+       
+       /**
+        * Get the contained canvas.
+        * 
+        * @return The contained canvas.
+        */
+       public Canvas getCanvas() {
+               return canvas;
+       }
+       
+       
+       /**
+        * Returns the shell associated with the canvas.
+        * 
+        * @return The shell.
+        */
+       public Shell getShell() {
+               return canvas.getShell();
+       }
+       
+       
+       /**
+        * Get the state of the timer.
+        * 
+        * @return The timer state.
+        */
+       public State getState() {
+               return state;
+       }
+       
+       
+       /**
+        * Add a state change listener.
+        * 
+        * @param listener
+        *          The listener.
+        */
+       public void addStateListener(StateListener listener) {
+               stateListeners.add(listener);
+       }
+       
+       
+       /**
+        * Remove a state change listener.
+        * 
+        * @param listener
+        *          The listener.
+        */
+       public void removeStateListener(StateListener listener) {
+               stateListeners.remove(listener);
+       }
+       
+       
+       /**
+        * Add a time-out listener.
+        * 
+        * @param listener
+        *          The listener.
+        */
+       public void addTimeoutListener(TimeoutListener listener) {
+               timeoutListeners.add(listener);
+       }
+       
+       
+       /**
+        * Remove a time-out listener.
+        * 
+        * @param listener
+        *          The listener.
+        */
+       public void removeTimeoutListener(TimeoutListener listener) {
+               timeoutListeners.remove(listener);
+       }
+       
+       
+       /**
+        * Returns an estimate of the elapsed time, in seconds.
+        * 
+        * @return The elapsed time.
+        */
+       public int getElapsed() {
+               return time - remaining;
+       }
+       
+       
+       /**
+        * Set the timeout for the timer, in seconds.
+        * 
+        * @param seconds
+        *          The number of seconds on the timer.
+        * @throws IllegalStateException
+        *          If {@link #canSet()} is <code>false</code>.
+        */
+       public void set(int seconds) throws IllegalStateException {
+               switch (state) {
+               case Initial:
+               case Ready:
+                       time = seconds;
+                       remaining = time;
+                       break;          
+               default:
+                       throw new IllegalStateException();
+               }
+               enter(State.Ready);
+               
+               repaint();
+       }
+       
+       
+       /**
+        * Returns <code>true</code> if set can be called. Set cannot be called when
+        * the timer is running or paused.
+        * 
+        * @return <code>true</code> if set can be called.
+        */
+       public boolean canSet() {
+               switch (state) {
+               case Initial:
+               case Ready:
+                       return true;
+               }
+               return false;
+       }
+       
+       
+       /**
+        * Start the timer. A new thread will control the timer count-down, so this
+        * method returns once it has started.
+        * 
+        * @throws IllegalStateException
+        *           If {@link #canStart()} is <code>false</code>.
+        */
+       public void start() throws IllegalStateException {
+               switch (state) {
+               case Ready:
+                       ticker = new Ticker(this, 1000);
+                       ticker.start();
+                       break;
+               case Paused:
+                       ticker.resume();
+                       break;
+               default:
+                       throw new IllegalStateException();
+               }
+               
+               enter(State.Running);
+               
+               repaint();
+       }
+       
+       
+       /**
+        * Returns <code>true</code> if start can be called. Start cannot be called
+        * when the timer is in it's initial or running state.
+        * 
+        * @return <code>true</code> if start can be called.
+        */
+       public boolean canStart() {
+               switch (state) {
+               case Ready:
+               case Paused:
+                       return true;
+               }
+               return false;
+       }
+       
+       
+       /**
+        * Pause the count-down. Temporarily suspends the count-down thread.
+        * 
+        * @throws IllegalStateException
+        *           If {@link #canPause()} is <code>false</code>.
+        */
+       public void pause() throws IllegalStateException {
+               switch (state) {
+               case Running:
+                       ticker.pause();
+                       break;
+               case Paused:
+                       break;
+               default:
+                       throw new IllegalStateException();
+               }
+               
+               enter(State.Paused);
+               
+               repaint();
+       }
+       
+       
+       /**
+        * Returns <code>true</code> if pause can be called. Pause cannot be called
+        * when the timer is in it's initial or ready state.
+        * 
+        * @return <code>true</code> if pause can be called.
+        */
+       public boolean canPause() {
+               switch (state) {
+               case Running:
+               case Paused:
+                       return true;
+               }
+               return false;
+       }
+       
+       
+       /**
+        * Reset the timer. Causes the timer to stop and return to the ready
+        * state, reseting the time-out to the last one set.
+        * 
+        * @throws IllegalStateException
+        *           If {@link #canReset()} is <code>false</code>.
+        */
+       public void reset() throws IllegalStateException {
+               switch (state) {
+               case Ready:
+                       break;
+               case Running:
+               case Paused:
+                       ticker.stop();
+                       ticker = null;
+                       remaining = time;
+                       break;
+               default:
+                       throw new IllegalStateException();
+               }
+               
+               enter(State.Ready);
+               
+               repaint();
+       }
+       
+       
+       /**
+        * Returns <code>true</code> if reset can be called. Reset cannot be called
+        * when the timer is in it's initial state.
+        * 
+        * @return <code>true</code> if reset can be called.
+        */
+       public boolean canReset() {
+               switch (state) {
+               case Ready:
+               case Running:
+               case Paused:
+                       return true;
+               }
+               return false;
+       }
+       
+       
+       /**
+        * Clear the timer. Returns the timer to its initial state, stopping
+        * it if necessary.
+        */
+       public void clear() {
+               switch (state) {
+               case Initial:
+                       break;
+               case Ready:
+                       time = 0;
+                       remaining = 0;
+                       break;
+               case Running:
+               case Paused:
+                       ticker.stop();
+                       ticker = null;
+                       remaining = 0;
+                       time = 0;
+                       break;
+               }
+               
+               enter(State.Initial);
+               
+               repaint();
+       }
+       
+       
+       /**
+        * Returns <code>true</code> if clear can be called.
+        * 
+        * @return Always returns <code>true</code>.
+        */
+       public boolean canClear() {
+               return true;
+       }
+       
+       
+       /**
+        * Tell the timer to repaint itself.
+        */
+       public void repaint() {
+               if (!canvas.isDisposed()) {
+                       canvas.redraw();
+               }
+       }
+       
+       
+       /**
+        * Called at each ticker tick interval. Should not be invoked by clients.
+        */
+       public void tick(final TickerEvent evt) {
+               if (canvas.isDisposed()) {
+                       // Widget is disposed, ignore timer events
+                       return;
+               }
+               
+               long elapsed = evt.getElapsed();
+               int remaining = time - (int) (elapsed / 1000); 
+               
+               if (remaining <= 0) {
+                       // We're done
+                       this.remaining = 0;
+                       
+                       // Stop and nullify ticker
+                       if (ticker != null) {
+                               ticker.stopLater();
+                               ticker = null;
+                       }
+                       
+                       // Enqueue the ui update the event dispatch thread
+                       canvas.getDisplay().asyncExec(new Runnable() {
+                               public void run() {
+                                       enter(State.Initial);
+                                       
+                                       // repaint
+                                       repaint();
+                                       
+                                       // fire timeout event
+                                       fireTimeoutEvent();
+                               }
+                       });
+               
+               } else if (this.remaining != remaining) {
+               
+                       // Update remaining 
+                       this.remaining = remaining;
+                       
+                       // Enqueue a repaint
+                       canvas.getDisplay().asyncExec(new Runnable() {
+                               public void run() {
+                                       // repaint
+                                       repaint();
+                               }
+                       });
+               }
+       }
+       
+       
+       /**
+        * Enter the given state.
+        * 
+        * @param state The state.
+        */
+       private void enter(State state) {
+               if (this.state != state) {
+                       this.state = state;
+                       fireStateChanged();
+               }
+       }
+       
+       
+       /**
+        * Fires a state changed event.
+        */
+       private void fireStateChanged() {
+               if (!stateListeners.isEmpty()) {
+                       StateEvent evt = new StateEvent(this);
+                       for (StateListener s : stateListeners) {
+                               s.stateChanged(evt);
+                       }
+               }
+       }
+
+
+       /**
+        * Sends a timeout event to listeners.
+        */
+       private void fireTimeoutEvent() {
+               if (!timeoutListeners.isEmpty()) {
+                       TimeoutEvent evt = new TimeoutEvent(this);
+                       for (TimeoutListener t : timeoutListeners) {
+                               t.timeoutOccured(evt);
+                       }
+               }
+       }
+       
+       
+       /**
+        * Paints the timer.
+        * 
+        * @param gc
+        *          The graphics context.
+        */
+       private void paint(GC gc) {
+               gc.setFont(getTimerFont());
+               
+               int ss = remaining % 60;
+               int mm = (remaining % 3600) / 60;
+               int hh = remaining / 3600;
+               
+               String timestr = formatTime(ss, mm, hh);
+               
+               Point t = getStringDimensions(gc, timestr);
+               Point c = getCanvasDimension();
+               
+               int x = c.x / 2 - t.x / 2;
+               int y = c.y / 2 - t.y / 2;
+               
+               if (remaining < 20 && state != State.Initial) {
+                       gc.setForeground(getWarningColor());
+               } else {
+                       gc.setForeground(getTimerColor());
+               }
+               
+               gc.drawString(timestr, x, y);
+       }
+       
+
+       /**
+        * Tidies native resources. Called automatically.
+        */
+       private void dispose() {
+               if (font != null) {
+                       font.dispose();
+                       font = null;
+               }
+       }
+       
+       
+       /**
+        * Formats a time string.
+        */
+       private String formatTime(int ss, int mm, int hh) {
+               String timestr;
+               if (hh == 0) {
+                       timestr = String.format("%02d:%02d", mm, ss);
+               } else {
+                       timestr = String.format("%02d:%02d:%02d", hh, mm, ss);
+               }
+               return timestr;
+       }
+       
+       
+       /**
+        * Returns the dimensions of a given string as drawn with the current font on
+        * the given graphics context.
+        */
+       private static Point getStringDimensions(GC gc, String str) {
+               int x = 0;
+               for (int i = 0; i < str.length(); i++) {
+                       x += gc.getAdvanceWidth(str.charAt(i));
+               }
+               int y = gc.getFontMetrics().getHeight();
+               return new Point(x,y);
+       }
+       
+       
+       /**
+        * Returns the dimensions of the canvas as a point.
+        * 
+        * @return A point where x is the width and y is the height.
+        */
+       private Point getCanvasDimension() {
+               Rectangle bounds = canvas.getBounds();
+               return new Point(bounds.width, bounds.height);
+       }
+       
+
+       private Color getWarningColor() {
+               return getSystemColor(SWT.COLOR_RED);
+       }
+       
+       
+       private Color getTimerColor() {
+               return getSystemColor(SWT.COLOR_DARK_BLUE);
+       }
+       
+       
+       private Font getTimerFont() {
+               if (font == null) {
+                       font = new Font(canvas.getDisplay(), "Sans", 30, SWT.NONE);
+               }
+               return font;
+       }
+       
+       
+       private Color getSystemColor(int id) {
+               return canvas.getDisplay().getSystemColor(id);
+       }
+
+       public static void main(String[] args) {
+               Display display = new Display();
+               Shell shell = new Shell(display, SWT.SHELL_TRIM);
+               shell.setBounds(800, 100, 220, 200);
+               shell.setLayout(new FillLayout());
+               
+               SwtTimer timer = new SwtTimer(shell, SWT.NONE);
+               timer.set(120);
+               timer.start();
+               
+               shell.open();
+               while (!shell.isDisposed()) {
+                       if (!display.readAndDispatch()) {
+                               display.sleep();
+                       }
+               }
+               display.dispose();
+       }
+       
+}
diff --git a/image_annotation/src/ie/dcu/apps/ist/widgets/Ticker.java b/image_annotation/src/ie/dcu/apps/ist/widgets/Ticker.java
new file mode 100644 (file)
index 0000000..c2d48ab
--- /dev/null
@@ -0,0 +1,246 @@
+package ie.dcu.apps.ist.widgets;
+
+import ie.dcu.apps.ist.event.*;
+
+
+public class Ticker implements Runnable {
+       private final TickerListener listener;
+       
+       private Thread thread   = null;
+       private boolean pause   = false;
+       private boolean stop    = false; 
+       private long napTime    = 100;
+       private long interval   = 1000;
+       private long elapsed    = 0;
+       private long startTime  = 0;
+       private long pausedTime = 0;
+       
+       // State variables
+       private boolean paused  = false;
+       private boolean stopped = true;
+       
+       public Ticker(TickerListener listener) {
+               
+               // Check listener
+               if (listener == null) {
+                       throw new IllegalArgumentException();
+               }
+               
+               this.listener = listener;
+       }
+       
+       
+       public Ticker(TickerListener listener, long interval) {
+               
+               // Check listener
+               if (listener == null) {
+                       throw new IllegalArgumentException();
+               }
+               
+               // Check interval
+               if (interval < 0) {
+                       throw new IllegalArgumentException();
+               }
+               
+               // Assign
+               this.listener = listener;
+               this.interval = interval;
+               this.napTime  = interval / 10;
+       }
+       
+       
+       public synchronized long elapsed() {
+               return elapsed;
+       }
+       
+       
+       public void start() {
+               if (thread != null) {
+                       throw new IllegalStateException("Cannot restart threads");
+               }
+               thread = new Thread(this, "TimerThread");
+               thread.start();
+       }
+       
+       
+       public void run() {
+               
+               synchronized (this) {
+                       stopped = false;
+               }
+               
+               // Set start time
+               startTime = System.currentTimeMillis();
+               
+               // Loop
+               while (true) {
+                       
+                       // Yawn! Z Z z z z Z Z Z z z z Z Z Z ...
+                       sleep(napTime);
+                       
+                       // Wait while thread is paused
+                       synchronized (this) {
+                               if (pause) {
+                                       
+                                       // Remember when pausing started
+                                       long now = System.currentTimeMillis();
+                                       
+                                       // Set paused flag to true and notify
+                                       paused = true;
+                                       notifyAll();
+                                       
+                                       // Wait until woken up
+                                       while (paused) doWait();
+                                       
+                                       // Add duration we've been paused for
+                                       pausedTime += System.currentTimeMillis() - now;
+                                       
+                                       // Clear pause flag && notify
+                                       pause = false;
+                                       notifyAll();
+                               }
+                       }
+                       
+                       // Check for stop flag
+                       synchronized (this) {
+                               if (stop) {
+                                       stopped = true;
+                                       notifyAll();
+                                       break;
+                               }
+                       }
+                       
+                       // HI-HO-HI-HO ...
+                       
+                       work();
+               }
+       }
+       
+       
+       private void work() { 
+               boolean event = false;
+               
+               synchronized (this) {
+                       // Calculate total elapsed time in milliseconds
+                       long now = System.currentTimeMillis();
+                       long elapsed = now - (startTime + pausedTime); 
+                       
+                       // Calculate time elapsed since last event
+                       long sinceLast = elapsed - this.elapsed;
+                       if (interval <= sinceLast) {
+                               
+                               // Compensate for any difference
+                               long diff = sinceLast - interval;
+                               
+                               // Its time for another event
+                               this.elapsed = elapsed - diff;
+                               
+                               // Fire event flag
+                               event = true;
+                       }
+               }
+               
+               // Do event
+               if (event) {
+                       synchronized (listener) {
+                               listener.tick(new TickerEvent(this, elapsed));
+                       }
+               }
+       }
+
+
+       public void pause() {
+               // Pause running thread
+               synchronized (this) {
+                       pause = true;
+                       
+                       // Wait for pause to occur
+                       while (!paused) doWait();
+               }
+       }
+       
+       
+       public void resume() {
+               // Wake up paused threads
+               synchronized (this) {
+                       if (paused) {
+                               paused = false;
+                               notifyAll();
+                       }
+                       
+                       while (pause) doWait();
+               }
+       }
+       
+       
+       public boolean isPaused() {
+               synchronized (this) {
+                       return paused;
+               }
+       }
+       
+       
+       public void stop() {
+               
+               synchronized (this) {
+                       
+                       // Resume paused threads
+                       if (paused) {
+                               paused = false;
+                               notifyAll();
+                       }
+                       
+                       while (pause) doWait();
+                       
+                       // Stop
+                       stop = true;
+                       
+                       // Wait until stop block reached
+                       while (!stopped) doWait();
+               }
+       }
+       
+       
+       public void stopLater() {
+               synchronized (this) {
+                       
+                       // Resume paused threads
+                       if (paused) {
+                               paused = false;
+                               notifyAll();
+                       }
+                       
+                       while (pause) doWait();
+                       
+                       // Stop
+                       stop = true;
+               }
+       }
+       
+       
+       public boolean isStopped() {
+               synchronized (this) {
+                       return stopped;
+               }
+       }
+       
+       
+       private void sleep(long millis) {
+               try {
+                       Thread.sleep(millis);
+               } catch (InterruptedException e) {
+                       // Ignore
+               }
+       }
+       
+       
+       private void doWait() {
+               try {
+                       wait();
+               } catch (InterruptedException e) {
+                       // ignore
+               }
+       }
+}
+
+