Skip to content

Commit 4d332c7

Browse files
authored
Merge pull request #59 from mfl28/feature/add-help-and-program-version-info
Add help menu and program version info
2 parents cc1e2ff + e08d9c2 commit 4d332c7

File tree

7 files changed

+100
-14
lines changed

7 files changed

+100
-14
lines changed

src/main/java/com/github/mfl28/boundingboxeditor/BoundingBoxEditorApp.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public static void main(String[] args) {
4949

5050
@Override
5151
public void start(Stage primaryStage) {
52-
final Controller controller = new Controller(primaryStage);
52+
final Controller controller = new Controller(primaryStage, getHostServices());
5353
final Scene scene = createSceneFromParent(controller.getView());
5454

5555
scene.getStylesheets().add(getClass().getResource(STYLESHEET_PATH).toExternalForm());

src/main/java/com/github/mfl28/boundingboxeditor/controller/Controller.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.github.mfl28.boundingboxeditor.utils.ImageUtils;
4444
import jakarta.ws.rs.client.Client;
4545
import jakarta.ws.rs.client.ClientBuilder;
46+
import javafx.application.HostServices;
4647
import javafx.application.Platform;
4748
import javafx.beans.property.BooleanProperty;
4849
import javafx.beans.property.SimpleBooleanProperty;
@@ -84,6 +85,10 @@
8485
public class Controller {
8586
private static final String PROGRAM_NAME = "Bounding Box Editor";
8687
private static final String PROGRAM_NAME_EXTENSION_SEPARATOR = " - ";
88+
private static final String GITHUB_WIKI_URL = "https://github.com/mfl28/BoundingBoxEditor/wiki";
89+
private static final String PROGRAM_VERSION = "2.5.0";
90+
private static final String PROGRAM_LICENSE = "GPL-3.0";
91+
private static final String PROGRAM_IDENTIFIER = PROGRAM_NAME + " " + PROGRAM_VERSION;
8792
private static final String OPEN_FOLDER_ERROR_DIALOG_TITLE = "Image Folder Loading Error";
8893
private static final String OPEN_FOLDER_ERROR_DIALOG_HEADER = "The selected folder is not a valid image folder.";
8994
private static final String SAVE_IMAGE_ANNOTATIONS_DIRECTORY_CHOOSER_TITLE = "Save Image Annotations to Folder";
@@ -172,6 +177,7 @@ public class Controller {
172177
private final BoundingBoxPredictorService boundingBoxPredictorService = new BoundingBoxPredictorService();
173178
private final ModelNameFetchService modelNameFetchService = new ModelNameFetchService();
174179
private final Stage stage;
180+
private final HostServices hostServices;
175181
private final MainView view = new MainView();
176182
private final Model model = new Model();
177183
private final ListChangeListener<BoundingShapeViewable> boundingShapeCountPerCategoryListener =
@@ -193,9 +199,11 @@ public class Controller {
193199
*
194200
* @param mainStage the stage that represents the top level container of all used ui-elements
195201
*/
196-
public Controller(final Stage mainStage) {
202+
public Controller(final Stage mainStage, final HostServices hostServices) {
197203
stage = mainStage;
198-
stage.setTitle(PROGRAM_NAME);
204+
this.hostServices = hostServices;
205+
206+
stage.setTitle(PROGRAM_IDENTIFIER);
199207
stage.getIcons().add(MainView.APPLICATION_ICON);
200208
stage.setOnCloseRequest(event -> {
201209
onRegisterExitAction();
@@ -650,6 +658,19 @@ public void onRegisterSettingsCancelCloseAction() {
650658
view.getInferenceSettingsView().setAllFieldsValid();
651659
}
652660

661+
public void onRegisterDocumentationAction() {
662+
hostServices.showDocument(GITHUB_WIKI_URL);
663+
}
664+
665+
public void onRegisterAboutAction() {
666+
MainView.displayTextInfoDialog(
667+
"About " + PROGRAM_NAME,
668+
PROGRAM_NAME,
669+
"Version: " + PROGRAM_VERSION +
670+
"\nLicense: " + PROGRAM_LICENSE,
671+
stage);
672+
}
673+
653674
void makeClientAvailable() {
654675
if(client == null) {
655676
client = ClientBuilder.newBuilder()
@@ -1304,7 +1325,7 @@ private void updateViewImageFiles() {
13041325

13051326
private void updateStageTitle() {
13061327
ImageMetaData currentImageMetaData = model.getCurrentImageMetaData();
1307-
stage.setTitle(PROGRAM_NAME + PROGRAM_NAME_EXTENSION_SEPARATOR
1328+
stage.setTitle(PROGRAM_IDENTIFIER + PROGRAM_NAME_EXTENSION_SEPARATOR
13081329
+ model.getCurrentImageFilePath() + " " + currentImageMetaData.getDimensionsString());
13091330
}
13101331

@@ -1526,7 +1547,7 @@ private void clearViewAndModel() {
15261547
imagePane.removeAllCurrentBoundingShapes();
15271548
view.getCurrentBoundingShapes().removeListener(boundingShapeCountPerCategoryListener);
15281549

1529-
stage.setTitle(PROGRAM_NAME);
1550+
stage.setTitle(PROGRAM_IDENTIFIER);
15301551

15311552
ObjectCategoryTableView objectCategoryTableView = view.getObjectCategoryTable();
15321553
objectCategoryTableView.getItems().clear();

src/main/java/com/github/mfl28/boundingboxeditor/ui/MainView.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,11 @@ public void displaySettingsDialog(Controller controller, Window owner) {
550550
settingsDialog.showAndWait();
551551
}
552552

553+
554+
public static void displayTextInfoDialog(String title, String header, String content, Window owner) {
555+
displayInfoAlert(title, header, content, null, owner);
556+
}
557+
553558
public Optional<Window> getSettingsWindow() {
554559
return Window.getWindows()
555560
.stream()
@@ -646,14 +651,16 @@ private static void displayInfoAlert(String title, String header, String content
646651
((Stage) alert.getDialogPane().getScene().getWindow()).getIcons().add(APPLICATION_ICON);
647652
alert.initOwner(owner);
648653

649-
GridPane.setVgrow(additionalInfoNode, Priority.ALWAYS);
650-
GridPane.setHgrow(additionalInfoNode, Priority.ALWAYS);
654+
if(additionalInfoNode != null) {
655+
GridPane.setVgrow(additionalInfoNode, Priority.ALWAYS);
656+
GridPane.setHgrow(additionalInfoNode, Priority.ALWAYS);
651657

652-
GridPane expandableContent = new GridPane();
653-
expandableContent.setMaxWidth(Double.MAX_VALUE);
654-
expandableContent.add(additionalInfoNode, 0, 0);
658+
GridPane expandableContent = new GridPane();
659+
expandableContent.setMaxWidth(Double.MAX_VALUE);
660+
expandableContent.add(additionalInfoNode, 0, 0);
655661

656-
alert.getDialogPane().setExpandableContent(expandableContent);
662+
alert.getDialogPane().setExpandableContent(expandableContent);
663+
}
657664
alert.showAndWait();
658665
}
659666

src/main/java/com/github/mfl28/boundingboxeditor/ui/MenuBarView.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ class MenuBarView extends MenuBar implements View {
6767
private static final String SETTINGS_TEXT = "Se_ttings";
6868
private static final String SETTINGS_ICON_ID = "settings-icon";
6969
private static final String FILE_SETTINGS_MENU_ITEM_ID = "file-settings-menu-item";
70+
private static final String HELP_MENU_TEXT = "_Help";
71+
private static final String HELP_MENU_ID = "help-menu";
72+
private static final String DOCUMENTATION_TEXT = "_Documentation";
73+
private static final String ABOUT_TEXT = "_About";
74+
private static final String DOCUMENTATION_MENU_ITEM_ID = "documentation-menu-item";
75+
private static final String ABOUT_MENU_ITEM_ID = "about-menu-item";
7076

7177
private final MenuItem fileOpenFolderItem = new MenuItem(OPEN_FOLDER_TEXT, createIconRegion(OPEN_FOLDER_ICON_ID));
7278
private final Menu fileExportAnnotationsMenu = new Menu(SAVE_TEXT, createIconRegion(SAVE_ICON_ID));
@@ -83,12 +89,14 @@ class MenuBarView extends MenuBar implements View {
8389
private final MenuItem fileExitItem = new MenuItem(EXIT_TEXT, createIconRegion(EXIT_ICON_ID));
8490
private final CheckMenuItem viewMaximizeImagesItem = new CheckMenuItem(MAXIMIZE_IMAGES_TEXT);
8591
private final CheckMenuItem viewShowImagesPanelItem = new CheckMenuItem(SHOW_IMAGE_FILE_EXPLORER_TEXT);
92+
private final MenuItem documentationMenuItem = new MenuItem(DOCUMENTATION_TEXT);
93+
private final MenuItem aboutMenuItem = new MenuItem(ABOUT_TEXT);
8694

8795
/**
8896
* Creates a new menu-bar UI-element.
8997
*/
9098
MenuBarView() {
91-
getMenus().addAll(createFileMenu(), createViewMenu());
99+
getMenus().addAll(createFileMenu(), createViewMenu(), createHelpMenu());
92100
setId(MAIN_MENU_BAR_ID);
93101
viewShowImagesPanelItem.setSelected(true);
94102
viewMaximizeImagesItem.setSelected(true);
@@ -132,6 +140,8 @@ public void connectToController(final Controller controller) {
132140
ImageAnnotationLoadStrategy.Type.JSON));
133141
fileExitItem.setOnAction(action -> controller.onRegisterExitAction());
134142
settingsMenuItem.setOnAction(action -> controller.onRegisterSettingsAction());
143+
documentationMenuItem.setOnAction(action -> controller.onRegisterDocumentationAction());
144+
aboutMenuItem.setOnAction(action -> controller.onRegisterAboutAction());
135145
}
136146

137147
/**
@@ -199,6 +209,21 @@ private Menu createViewMenu() {
199209
return viewMenu;
200210
}
201211

212+
private Menu createHelpMenu() {
213+
Menu helpMenu = new Menu(HELP_MENU_TEXT);
214+
helpMenu.setId(HELP_MENU_ID);
215+
216+
helpMenu.getItems().addAll(
217+
documentationMenuItem,
218+
aboutMenuItem
219+
);
220+
221+
documentationMenuItem.setId(DOCUMENTATION_MENU_ITEM_ID);
222+
aboutMenuItem.setId(ABOUT_MENU_ITEM_ID);
223+
224+
return helpMenu;
225+
}
226+
202227
private Region createIconRegion(String cssId) {
203228
Region region = new Region();
204229
region.setId(cssId);

src/test/java/com/github/mfl28/boundingboxeditor/BoundingBoxEditorTestBase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ protected void waitUntilCurrentImageIsLoaded(TestInfo testinfo) {
205205
@Start
206206
protected void onStart(Stage stage) {
207207
Platform.setImplicitExit(false);
208-
controller = new Controller(stage);
208+
controller = new Controller(stage, null);
209209
mainView = controller.getView();
210210
model = controller.getModel();
211211
// To make sure that the window is on top of all other windows at the start.

src/test/java/com/github/mfl28/boundingboxeditor/controller/ControllerTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ void onReloadAnnotations_afterImageFilesReopened_shouldCorrectlyDisplayBoundingS
10481048
WaitForAsyncUtils.waitForFxEvents();
10491049
timeOutAssertServiceSucceeded(controller.getImageMetaDataLoadingService(), testinfo);
10501050

1051-
verifyThat(controller.getStage().getTitle(), Matchers.startsWith("Bounding Box Editor - "),
1051+
verifyThat(controller.getStage().getTitle(), Matchers.matchesRegex("^Bounding Box Editor \\d\\.\\d\\.\\d - .*$"),
10521052
saveScreenshot(testinfo));
10531053

10541054
verifyThat(mainView.getStatusBar().getCurrentEventMessage(),

src/test/java/com/github/mfl28/boundingboxeditor/ui/NoImageFolderOpenedBasicTests.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,39 @@ private void verifyMenuBarFunctionality(FxRobot robot, TestInfo testinfo) {
218218
assertTrue(imageExplorerItem.isDisable(),
219219
() -> saveScreenshotAndReturnMessage(testinfo, "Image explorer item not " +
220220
"disabled"));
221+
222+
223+
timeOutClickOn(robot, "#help-menu", testinfo);
224+
225+
WaitForAsyncUtils.waitForFxEvents();
226+
227+
MenuItem documentationItem = getSubMenuItem(robot, "Help", "Documentation");
228+
assertTrue(documentationItem.isVisible(),
229+
() -> saveScreenshotAndReturnMessage(testinfo, "Documentation item not " +
230+
"visible"));
231+
assertFalse(documentationItem.isDisable(),
232+
() -> saveScreenshotAndReturnMessage(testinfo, "Documentation item not " +
233+
"enabled"));
234+
235+
MenuItem aboutItem = getSubMenuItem(robot, "Help", "About");
236+
assertTrue(aboutItem.isVisible(),
237+
() -> saveScreenshotAndReturnMessage(testinfo, "About item not " +
238+
"visible"));
239+
assertFalse(aboutItem.isDisable(),
240+
() -> saveScreenshotAndReturnMessage(testinfo, "About item not " +
241+
"enabled"));
242+
243+
timeOutClickOn(robot, "#help-menu", testinfo);
244+
WaitForAsyncUtils.waitForFxEvents();
245+
timeOutClickOn(robot, "#about-menu-item", testinfo);
246+
WaitForAsyncUtils.waitForFxEvents();
247+
248+
Stage aboutStage = timeOutGetTopModalStage(robot, "About Bounding Box Editor", testinfo);
249+
verifyThat(aboutStage, Matchers.notNullValue(), saveScreenshot(testinfo));
250+
251+
timeOutLookUpInStageAndClickOn(robot, aboutStage, "OK", testinfo);
252+
WaitForAsyncUtils.waitForFxEvents();
253+
timeOutAssertTopModalStageClosed(robot, "About Bounding Box Editor", testinfo);
221254
}
222255

223256
private void verifyNodeVisibilities(TestInfo testinfo) {

0 commit comments

Comments
 (0)