Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
029f03d
#1296: implemented basic IdeDialog Class
laim2003 Mar 27, 2026
89cfb67
#1296: Added basic context state manager class
laim2003 Mar 30, 2026
a53296d
#1785: Added basic question/confirmation modal implementation
laim2003 Mar 30, 2026
37cad74
#1296: implemented basic IdeDialog Class
laim2003 Mar 27, 2026
55a50ce
#1296: Added basic context state manager class
laim2003 Mar 30, 2026
3f1569f
#1785: Added basic question/confirmation modal implementation
laim2003 Mar 30, 2026
6ce99b3
Merge remote-tracking branch 'origin/#1296-implement-idecontext-for-g…
laim2003 Mar 30, 2026
7ef65f3
#1785: - Added logging to IdeGuiStateManager.
laim2003 Mar 30, 2026
1764b2f
#1724: implemented basic gui state management
laim2003 Apr 7, 2026
ddd3e5f
#1802: implemented basic gui state management
laim2003 Apr 7, 2026
9c5a720
Merge remote-tracking branch 'origin/#1802-state-management-implement…
laim2003 Apr 7, 2026
b28e216
#1802: removed a few changes so this branch can be the base for other…
laim2003 Apr 7, 2026
234e98b
#1802: disabled javadoc warning
laim2003 Apr 9, 2026
1c4e766
#1802: - fixed AppBaseTest being stuck
laim2003 Apr 9, 2026
6fc3884
Merge branch 'main' into #1802-state-management-implementation
laim2003 Apr 14, 2026
2026757
#1802: Added ProjectManager class to handle business logic of reading…
laim2003 Apr 14, 2026
c76e185
#1802: Updated IdeGuiStateManager to also update its projectManager, …
laim2003 Apr 14, 2026
6f92d93
#1802: javafx updated to java 25
laim2003 Apr 15, 2026
9f741a5
Merge branch 'main' into #1802-state-management-implementation
laim2003 Apr 21, 2026
48fe018
Revert "#1802: javafx updated to java 25"
laim2003 Apr 21, 2026
e0ad015
#1803: added DI for IDE_ROOT in GuiStateManager
laim2003 Apr 21, 2026
2c9fc55
#1802: added DI for IDE_ROOT in GuiStateManager
laim2003 Apr 21, 2026
2b62c60
Merge remote-tracking branch 'origin/#1802-state-management-implement…
laim2003 Apr 21, 2026
40ff54e
#1802: Workaround for IDE_ROOT=null issue. The ideRoot in GuiStateMan…
laim2003 Apr 21, 2026
0b67210
#1802: removed redundant DI variant of switchContext() (DI via getIns…
laim2003 Apr 21, 2026
2e15d60
#1802: Added tests for GuiStateManager
laim2003 Apr 21, 2026
10cf940
Merge branch 'main' into #1802-state-management-implementation
laim2003 Apr 23, 2026
5f0b40a
#1802: Extracted mock IDE_ROOT logic into seperate class that can be …
laim2003 Apr 23, 2026
3b567ef
Merge remote-tracking branch 'origin/#1802-state-management-implement…
laim2003 Apr 23, 2026
e406b65
#1802: added ProjectManagerTest
laim2003 Apr 23, 2026
e0e2d9d
#1802: Detached startContext creation from switchContext in IdeGuiSta…
laim2003 Apr 24, 2026
d70f460
#1802: Fixed bug in IdeGuiStateManagerTest leading to test failure
laim2003 Apr 24, 2026
d6aace2
Merge branch 'main' into #1802-state-management-implementation
laim2003 Apr 24, 2026
9c78eac
#1802: Added ContextChangeListener; improved thread safety of IdeGuiS…
laim2003 Apr 24, 2026
4c84bb9
Merge branch 'main' into #1802-state-management-implementation
laim2003 Apr 24, 2026
69055d9
#1802: tests now use AbstractIdeContextTest
laim2003 Apr 28, 2026
9978ce9
#1802: Updated UI logic to:
laim2003 Apr 28, 2026
ac3a045
#1802: cleaned up ProjectManagerTest, fixed AppBaseTest to follow new…
laim2003 Apr 28, 2026
6c44432
#1802: cleaned up IdeGuiStateManagerTest
laim2003 Apr 28, 2026
c30c2ea
Merge branch 'main' into #1802-state-management-implementation
laim2003 Apr 28, 2026
1e8b556
#1802: cleaned up ProjectManagerTest to use FileUtils instead of own …
laim2003 Apr 28, 2026
d51111d
Merge remote-tracking branch 'origin/#1802-state-management-implement…
laim2003 Apr 28, 2026
98a7072
Merge branch 'main' into #1802-state-management-implementation
laim2003 May 5, 2026
c55a3a3
Merge branch 'main' into #1802-state-management-implementation
laim2003 May 12, 2026
4747bae
#1802: cleaned up test folders, fixed wrong Logger used in ProjectMan…
laim2003 May 26, 2026
e03949d
#1802: cleaned up test folders #2
laim2003 May 26, 2026
e4e5bd9
#1802: cleaned up test folders nr. 3
laim2003 May 26, 2026
44791ef
Merge branch 'main' into #1802-state-management-implementation
laim2003 May 26, 2026
dab292f
#1802: removed caching from ProjectManager
laim2003 May 26, 2026
11a9546
#1802: cleanup
laim2003 May 26, 2026
4781ea5
#1802: cleanup
laim2003 May 26, 2026
9ee0bc2
#1802: cleanup of ide.properties
laim2003 May 26, 2026
07b7773
#1936: Implement i18n locale-switching
KarimALotfy May 27, 2026
5943b23
#1936: Add to CHANGELOG.adoc
KarimALotfy May 27, 2026
01d696b
Merge "PR-1807" to "feature/1936-improve-localization-of-gui"
KarimALotfy May 28, 2026
df6f21b
Merge main into "feature/1936-improve-localization-of-gui"
KarimALotfy May 28, 2026
638c227
#1928: Initial Commit
KarimALotfy Jun 5, 2026
975ed97
#1928: update update/upgrade UI
KarimALotfy Jun 15, 2026
cc1ebdb
#1928: Refactored flow of Update to match that of Upgrade, with an in…
KarimALotfy Jun 15, 2026
f4c3378
#1928: Remove unneeded test
KarimALotfy Jun 16, 2026
519a8bb
#1928: Merge "main" into "feature/1936-improve-localization-of-gui"
KarimALotfy Jun 16, 2026
aaa1763
#1928: Remove duplicated Imports
KarimALotfy Jun 16, 2026
3441ed4
#1928: Align structure of ide-projects with main
KarimALotfy Jun 16, 2026
caa4ad1
Merge "feature/1936-improve-localization-of-gui" into "feature/1928-s…
KarimALotfy Jun 16, 2026
db59208
#1928: Merging with main after resolving merge conflicts and aligning…
KarimALotfy Jul 8, 2026
41d3d99
#1928: Split logic of Update and Upgrade Controller into Service clas…
KarimALotfy Jul 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions gui/src/main/java/com/devonfw/ide/gui/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,31 +34,37 @@ public class App extends Application {

@Override
public void start(Stage primaryStage) throws IOException {
try {

TestGuiConfiguration.applyConfigOverrides();

this.primaryStage = primaryStage;
this.primaryStage = primaryStage;

this.nlsService = new NlsService(null);
this.nlsService = new NlsService(null);

Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
LOG.error("Uncaught exception in thread {}: {}", thread.getName(), throwable.getMessage(), throwable);
Platform.runLater(() -> new IdeDialog(IdeDialog.AlertType.ERROR, throwable.getMessage()).showAndWait());
}
);
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
LOG.error("Uncaught exception in thread {}: {}", thread.getName(), throwable.getMessage(), throwable);
Platform.runLater(() -> new IdeDialog(IdeDialog.AlertType.ERROR, throwable.getMessage()).showAndWait());
}
);

root = loadMainView();
root = loadMainView();

this.nlsService.addLocaleChangeListener(this::reloadMainView);
this.nlsService.addLocaleChangeListener(this::reloadMainView);

Rectangle2D bounds = Screen.getPrimary().getVisualBounds();
Scene scene = new Scene(root, bounds.getWidth() / 2, bounds.getHeight() / 2);
Rectangle2D bounds = Screen.getPrimary().getVisualBounds();
Scene scene = new Scene(root, bounds.getWidth() / 2, bounds.getHeight() / 2);

Image icon = new Image("com/devonfw/ide/gui/assets/devonfw.png");
primaryStage.getIcons().add(icon);
primaryStage.setTitle("IDEasy - version " + IdeVersion.getVersionString());
primaryStage.setScene(scene);
primaryStage.setMinWidth(scene.getWidth());
primaryStage.setMinHeight(scene.getHeight());
primaryStage.show();
Image icon = new Image("com/devonfw/ide/gui/assets/devonfw.png");
primaryStage.getIcons().add(icon);
primaryStage.setTitle("IDEasy - version " + IdeVersion.getVersionString());
primaryStage.setScene(scene);
primaryStage.setMinWidth(scene.getWidth());
primaryStage.setMinHeight(scene.getHeight());
primaryStage.show();
} catch (Throwable t) {
new IdeDialog(IdeDialog.AlertType.ERROR, "Failed to start IDEasy GUI: " + t.getMessage()).showAndWait();
}
}

@Override
Expand Down
86 changes: 75 additions & 11 deletions gui/src/main/java/com/devonfw/ide/gui/MainController.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -17,6 +19,8 @@
import com.devonfw.ide.gui.context.ProjectManager;
import com.devonfw.ide.gui.modal.IdeDialog;
import com.devonfw.ide.gui.nls.NlsService;
import com.devonfw.ide.gui.update.UpdateController;
import com.devonfw.ide.gui.update.UpgradeController;

/**
* Controller of the main screen of the dashboard GUI.
Expand All @@ -31,6 +35,9 @@ public class MainController {
@FXML
private ComboBox<String> selectedProject;

@FXML
private Label projectHeaderLabel;

@FXML
private ComboBox<String> selectedWorkspace;

Expand All @@ -49,30 +56,75 @@ public class MainController {
@FXML
private Button vsCodeOpen;

private final String directoryPath;
@FXML
private StackPane updateIndicator;

private final Map<String, Locale> languageMap;
@FXML
private StackPane upgradeIndicator;

private final UpdateController updateController;

private final UpgradeController upgradeController;

private final NlsService nlsService;

private final String directoryPath;

private final Map<String, Locale> languageMap;

/**
* Constructor
*/
public MainController(String directoryPath, NlsService nlsService) {
this(directoryPath, IdeGuiStateManager.getInstance().getProjectManager(), new UpdateController(IdeGuiStateManager.getInstance(), nlsService),
new UpgradeController(IdeGuiStateManager.getInstance(), nlsService), nlsService);
}

/**
* Constructor with injected dependencies.
*
* @param directoryPath IDE root path
* @param projectManager the project manager to use
* @param updateController update controller to use for project related update actions
* @param upgradeController upgrade controller to use for IDEasy upgrade actions
*/
public MainController(String directoryPath, ProjectManager projectManager, UpdateController updateController, UpgradeController upgradeController,
NlsService nlsService) {

LOG.debug("IDE_ROOT path={}", directoryPath);
this.directoryPath = directoryPath;
this.languageMap = new LinkedHashMap<>();
this.nlsService = nlsService;
this.projectManager = projectManager;
this.updateController = updateController;
this.upgradeController = upgradeController;

this.projectManager = IdeGuiStateManager.getInstance().getProjectManager();
}

@FXML
private void initialize() {
setProjectsComboBox();
initLanguageComboBox();
initUpgradeAndUpdateCheck();
}

private void initUpgradeAndUpdateCheck() {
try {
this.updateController.start(this.updateIndicator);
if (this.upgradeController != null) {
// Pass the indicator to the upgrade controller which will manage its visibility and dialog.
this.upgradeController.start(this.upgradeIndicator);
}
} catch (Exception e) {
LOG.debug("Failed to start update controller", e);
if (this.updateIndicator != null) {
this.updateIndicator.setVisible(false);
}
if (this.upgradeController != null && this.upgradeIndicator != null) {
// if upgrade controller failed to start, ensure indicator hidden
this.upgradeIndicator.setVisible(false);
}
}
}

private void initLanguageComboBox() {
Expand Down Expand Up @@ -148,7 +200,6 @@ private void openVsCode() {
openIDE("vscode");
}


private void setProjectsComboBox() {

assert (directoryPath != null) : "directoryPath is null! Please check the setup of your environment variables (IDE_ROOT)";
Expand All @@ -164,11 +215,14 @@ private void setProjectsComboBox() {

selectedWorkspace.setDisable(false);
});
selectedProject.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) -> {
projectHeaderLabel.setText(newVal != null ? newVal : "");
});
}

private void setWorkspaceComboBox() {

List<String> workspaces = null;
List<String> workspaces;
try {
workspaces = projectManager.getWorkspaceNames(selectedProject.getValue());
} catch (NotDirectoryException e) {
Expand All @@ -179,12 +233,18 @@ private void setWorkspaceComboBox() {
selectedWorkspace.getItems().addAll(workspaces);

selectedWorkspace.setOnAction(actionEvent -> {
updateContext(selectedProject.getValue(), selectedWorkspace.getValue());

androidStudioOpen.setDisable(false);
eclipseOpen.setDisable(false);
intellijOpen.setDisable(false);
vsCodeOpen.setDisable(false);
if (updateContext(selectedProject.getValue(), selectedWorkspace.getValue())) {
androidStudioOpen.setDisable(false);
eclipseOpen.setDisable(false);
intellijOpen.setDisable(false);
vsCodeOpen.setDisable(false);

if (this.updateController != null) {
this.updateController.onContextChanged(IdeGuiStateManager.getInstance().getCurrentContext());
}
// no-op: manual check button removed
}
});
}

Expand All @@ -198,12 +258,16 @@ private void openIDE(String inIde) {
.run();
}

private void updateContext(String selectedProjectName, String selectedWorkspaceName) {
private boolean updateContext(String selectedProjectName, String selectedWorkspaceName) {
try {
IdeGuiStateManager.getInstance().switchContext(selectedProjectName, selectedWorkspaceName);
return true;
} catch (FileNotFoundException e) {
IdeGuiStateManager.getInstance().clearCurrentContext();
IdeDialog errorDialog = new IdeDialog(IdeDialog.AlertType.ERROR, e.getMessage());
errorDialog.showAndWait();
// no-op: manual check button removed
return false;
}
}
}
61 changes: 61 additions & 0 deletions gui/src/main/java/com/devonfw/ide/gui/TestGuiConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.devonfw.ide.gui;

import com.devonfw.ide.gui.update.UpdateService;
import com.devonfw.tools.ide.version.IdeVersion;

/**
* Centralizes test/development configuration overrides via environment variables and system properties.
* <p>
* Supported overrides:
* <ul>
* <li>{@code IDE_VERSION}: Override the IDEasy version for testing version checks/upgrades</li>
* <li>{@code IDE_UPDATE_AVAILABLE}: Set to "true" to force update availability (for testing update flows)</li>
* </ul>
* <p>
* Usage: {@code IDE_UPDATE_AVAILABLE=true IDE_VERSION=1.0.0 java -jar ideasy-gui.jar}
* Or: {@code java -DIDE_UPDATE_AVAILABLE=true -DIDE_VERSION=1.0.0 -jar ideasy-gui.jar}
*/
public class TestGuiConfiguration {

private TestGuiConfiguration() {
// Utility class, no instances
}

/**
* Applies all test/development configuration overrides from environment variables and system properties.
* Call this early in the application lifecycle (before creating controllers).
*/
public static void applyConfigOverrides() {
applyVersionOverride();
applyUpdateAvailabilityOverride();
}

/**
* Applies IDE_VERSION override. If set, causes version checks and upgrades to use the mocked version.
*/
private static void applyVersionOverride() {
String versionOverride = System.getenv("IDE_VERSION");
if ((versionOverride == null) || versionOverride.isBlank()) {
versionOverride = System.getProperty("IDE_VERSION");
}
if ((versionOverride != null) && !versionOverride.isBlank()) {
IdeVersion.setMockVersionForTesting(versionOverride.trim());
}
}

/**
* Applies IDE_UPDATE_AVAILABLE override. If set to "true", update checks will report that an update is available
* (useful for testing the update flow without requiring actual updates to be present).
*/
private static void applyUpdateAvailabilityOverride() {
String updateOverride = System.getenv("IDE_UPDATE_AVAILABLE");
if ((updateOverride == null) || updateOverride.isBlank()) {
updateOverride = System.getProperty("IDE_UPDATE_AVAILABLE");
}
if ((updateOverride != null) && !updateOverride.isBlank()) {
boolean isAvailable = "true".equalsIgnoreCase(updateOverride.trim());
UpdateService.setMockUpdateAvailable(isAvailable);
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ public static IdeGuiStateManager getInstance() {
return Holder.INSTANCE;
}

/**
* Expose the internal start context used to create {@link com.devonfw.ide.gui.context.IdeGuiContext}s. This is needed by the GUI to perform global checks
* (like checking for IDEasy upgrades) without a selected project context.
*
* @return the {@link com.devonfw.tools.ide.context.IdeStartContextImpl} used by the GUI.
*/
public IdeStartContextImpl getStartContext() {

return this.startContext;
}

/**
* <strong><u>USE WITH CARE.</u></strong>
* This method is used in cases where the IDE_ROOT environment variable is not set, e.g. in test contexts on GitHub actions. This method will retrieve the
Expand Down Expand Up @@ -107,6 +118,14 @@ public synchronized IdeGuiContext switchContext(String projectName, String works
return this.currentContext;
}

/**
* Clears the currently selected project context.
*/
public synchronized void clearCurrentContext() {

this.currentContext = null;
}

/**
* @return the current {@link IdeGuiContext} based on the selected project. is <code>null</code>, if no context has been set via switchContext.
*/
Expand Down
Loading
Loading