Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 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
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
2 changes: 0 additions & 2 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,6 @@
</archive>
</configuration>
</execution>

<!-- jar for test classes -->
<execution>
<id>test-jar</id>
<goals>
Expand Down
22 changes: 11 additions & 11 deletions cli/src/test/java/com/devonfw/tools/ide/context/IdeContextTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@
import java.util.Properties;

import org.junit.jupiter.api.Test;
import com.devonfw.tools.ide.security.ToolVersionChoice;
import com.devonfw.tools.ide.tool.ToolEditionAndVersion;
import com.devonfw.tools.ide.security.ToolVulnerabilities;
import com.devonfw.tools.ide.version.VersionIdentifier;
import com.devonfw.tools.ide.version.VersionRange;
import com.devonfw.tools.ide.url.model.file.json.Cve;
import com.devonfw.tools.ide.tool.ToolEdition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -24,13 +17,20 @@
import com.devonfw.tools.ide.log.IdeLogLevel;
import com.devonfw.tools.ide.os.SystemInfo;
import com.devonfw.tools.ide.os.SystemInfoMock;
import com.devonfw.tools.ide.security.ToolVersionChoice;
import com.devonfw.tools.ide.security.ToolVulnerabilities;
import com.devonfw.tools.ide.tool.ToolEdition;
import com.devonfw.tools.ide.tool.ToolEditionAndVersion;
import com.devonfw.tools.ide.url.model.file.json.Cve;
import com.devonfw.tools.ide.variable.IdeVariables;
import com.devonfw.tools.ide.version.IdeVersion;
import com.devonfw.tools.ide.version.VersionIdentifier;
import com.devonfw.tools.ide.version.VersionRange;

/**
* Test of {@link IdeContext}.
*/
class IdeContextTest extends AbstractIdeContextTest {
public class IdeContextTest extends AbstractIdeContextTest {

private static final Logger LOG = LoggerFactory.getLogger(IdeContextTest.class);

Expand Down Expand Up @@ -284,7 +284,7 @@ void testFindBashOnSystemPathOnWindowsWithInvalidBashPathSet() {
@Test
void testQuestionWithMultipleOptions() {
IdeTestContext context = newContext(PROJECT_BASIC, null, false);
String[] options = {"option1", "option2"};
String[] options = { "option1", "option2" };
context.setAnswers("option1");
String result = context.question(options, "Which option?");
assertThat(result).isEqualTo("option1");
Expand All @@ -293,7 +293,7 @@ void testQuestionWithMultipleOptions() {
@Test
void testQuestionWithSingleOptionAndEmptyAnswer() {
IdeTestContext context = newContext(PROJECT_BASIC, null, false);
String[] options = {"onlyOption"};
String[] options = { "onlyOption" };
context.setAnswers(""); // Empty answer (Enter)
String result = context.question(options, "Which option?");
assertThat(result).isEqualTo("onlyOption");
Expand All @@ -306,7 +306,7 @@ void testQuestionWithSingleToolVersionChoiceAndEmptyAnswer() {
VersionIdentifier version = VersionIdentifier.of("17");
Cve cve = new Cve("CVE-2023-XXXX", 9.8, List.of(VersionRange.of("[17,18)")));
ToolVersionChoice choice = new ToolVersionChoice(new ToolEditionAndVersion(edition, version), "current", ToolVulnerabilities.of(List.of(cve)));
ToolVersionChoice[] options = {choice};
ToolVersionChoice[] options = { choice };

context.setAnswers(""); // Empty answer (Enter)
ToolVersionChoice result = context.question(options, "Which version?");
Expand Down
9 changes: 8 additions & 1 deletion gui/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>ide-cli</artifactId>
<classifier>tests</classifier>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
Expand Down Expand Up @@ -68,6 +67,14 @@
<artifactId>openjfx-monocle</artifactId>
<scope>test</scope>
</dependency>

<!-- required for using ide-cli testing classes -->
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>3.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
13 changes: 13 additions & 0 deletions gui/src/main/java/com/devonfw/ide/gui/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
Expand All @@ -10,6 +11,10 @@
import javafx.stage.Screen;
import javafx.stage.Stage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.devonfw.ide.gui.modal.IdeDialog;
import com.devonfw.tools.ide.variable.IdeVariables;
import com.devonfw.tools.ide.version.IdeVersion;

Expand All @@ -20,9 +25,17 @@ public class App extends Application {

Parent root;

private static final Logger LOG = LoggerFactory.getLogger(App.class);

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

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());
}
);

FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource("main-view.fxml"));
fxmlLoader.setController(
new MainController(System.getenv(IdeVariables.IDE_ROOT.getName()))
Expand Down
3 changes: 2 additions & 1 deletion gui/src/main/java/com/devonfw/ide/gui/AppLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

/**
* Launcher class for the App. Workaround for "Error: JavaFX runtime components are missing, and are required to run this application." Inspired by
* <ahref=https://stackoverflow.com/questions/56894627/how-to-fix-error-javafx-runtime-components-are-missing-and-are-required-to-ru>StackOverflow</a>
* <a href=https://stackoverflow.com/questions/56894627/how-to-fix-error-javafx-runtime-components-are-missing-and-are-required-to-ru>StackOverflow</a>
*/
public class AppLauncher {

@SuppressWarnings("MissingJavadoc")
public static void main(final String[] args) {

App.main(args);
Expand Down
92 changes: 43 additions & 49 deletions gui/src/main/java/com/devonfw/ide/gui/MainController.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package com.devonfw.ide.gui;

import java.io.IOException;
import java.nio.file.Files;
import java.io.FileNotFoundException;
import java.nio.file.Path;
import java.util.stream.Stream;
import java.util.List;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.context.IdeStartContextImpl;
import com.devonfw.tools.ide.log.IdeLogLevel;
import com.devonfw.tools.ide.log.IdeLogListenerBuffer;
import com.devonfw.ide.gui.context.IdeGuiStateManager;
import com.devonfw.ide.gui.context.ProjectManager;
import com.devonfw.ide.gui.modal.IdeDialog;

/**
* Controller of the main screen of the dashboard GUI.
Expand All @@ -23,6 +21,9 @@ public class MainController {

private static Logger LOG = LoggerFactory.getLogger(MainController.class);

private ProjectManager projectManager;


@FXML
private ComboBox<String> selectedProject;

Expand All @@ -49,8 +50,11 @@ public class MainController {
* Constructor
*/
public MainController(String directoryPath) {

LOG.debug("IDE_ROOT path={}", directoryPath);
this.directoryPath = directoryPath;

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

@FXML
Expand Down Expand Up @@ -83,66 +87,56 @@ private void openVsCode() {
openIDE("vscode");
}


private void setProjectsComboBox() {

assert (directoryPath != null) : "directoryPath is null! Please check the setup of your environment variables (IDE_ROOT)";

List<String> projects = projectManager.getProjectNames();

selectedProject.getItems().clear();
Path directory = Path.of(directoryPath);

if (Files.exists(directory) && Files.isDirectory(directory)) {
try (Stream<Path> subPaths = Files.list(directory)) {
subPaths
.filter(Files::isDirectory)
.map(Path::getFileName)
.map(Path::toString)
.filter(name -> !name.startsWith("_"))
.forEach(name -> selectedProject.getItems().add(name));
} catch (IOException e) {
throw new IllegalStateException("Failed to list projects!", e);
}
}
selectedProject.getItems().addAll(projects);

selectedProject.setOnAction(actionEvent -> {

projectValue = Path.of(selectedProject.getValue()).resolve(IdeContext.FOLDER_WORKSPACES);
setWorkspaceComboBox();

selectedWorkspace.setDisable(false);
});
}

private void setWorkspaceComboBox() {

List<String> workspaces = projectManager.getWorkspaceNames(selectedProject.getValue());

selectedWorkspace.getItems().clear();
selectedWorkspace.getItems().addAll(workspaces);

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

androidStudioOpen.setDisable(false);
eclipseOpen.setDisable(false);
intellijOpen.setDisable(false);
vsCodeOpen.setDisable(false);
selectedWorkspace.setValue("main");
this.workspaceValue = Path.of("main");
});
}

@FXML
private void setWorkspaceValue() {
private void openIDE(String inIde) {

selectedWorkspace.getItems().clear();
Path directory = Path.of(directoryPath).resolve(projectValue);
if (Files.exists(directory) && Files.isDirectory(directory)) {
try (Stream<Path> subPaths = Files.list(directory)) {
subPaths
.filter(Files::isDirectory)
.map(Path::getFileName)
.map(Path::toString)
.forEach(name -> selectedWorkspace.getItems().add(name));

} catch (IOException e) {
throw new RuntimeException("Error occurred while fetching workspace names.", e);
}
}
this.workspaceValue = Path.of(selectedWorkspace.getValue());
IdeGuiStateManager
.getInstance()
.getCurrentContext()
.getCommandletManager()
.getCommandlet(inIde)
.run();
}

private void openIDE(String inIde) {

final IdeLogListenerBuffer buffer = new IdeLogListenerBuffer();
IdeLogLevel logLevel = IdeLogLevel.INFO;
IdeStartContextImpl startContext = new IdeStartContextImpl(logLevel, buffer);
IdeGuiContext context = new IdeGuiContext(startContext, Path.of(this.directoryPath).resolve(this.projectValue).resolve(this.workspaceValue));
context.getCommandletManager().getCommandlet(inIde).run();
private void updateContext(String selectedProjectName, String selectedWorkspaceName) {
try {
IdeGuiStateManager.getInstance().switchContext(selectedProjectName, selectedWorkspaceName);
} catch (FileNotFoundException e) {
IdeDialog errorDialog = new IdeDialog(IdeDialog.AlertType.ERROR, e.getMessage());
errorDialog.showAndWait();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.devonfw.ide.gui.context;

/**
* Interface that notifies listeners of context changes.
*/
public interface GuiContextChangeListener {

/**
* This method is called when the context changes. It can be used to update the GUI based on the new context.
*
* @param newContext the new {@link IdeGuiContext}.
*/
void onContextChange(IdeGuiContext newContext);

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.devonfw.ide.gui;
package com.devonfw.ide.gui.context;

import java.nio.file.Path;

Expand All @@ -12,25 +12,26 @@
*/
public class IdeGuiContext extends AbstractIdeContext {


/**
* The constructor.
*
* @param startContext the {@link IdeStartContextImpl}.
* @param workingDirectory the optional {@link Path} to current working directory.
*/
public IdeGuiContext(IdeStartContextImpl startContext, Path workingDirectory) {

super(startContext, workingDirectory);
}

@Override
protected String readLine() {

return "";
}

@Override
public IdeProgressBar newProgressBar(String title, long size, String unitName, long unitSize) {

return new IdeProgressBarNone(title, 0, unitName, unitSize);
}

}
Loading
Loading