diff --git a/build.sh b/build.sh old mode 100755 new mode 100644 diff --git a/cobigen-cli/cli/pom.xml b/cobigen-cli/cli/pom.xml index 185117cc1c..c168fe1627 100644 --- a/cobigen-cli/cli/pom.xml +++ b/cobigen-cli/cli/pom.xml @@ -13,6 +13,7 @@ false + 18 @@ -24,6 +25,10 @@ com.devonfw.cobigen core-api + + com.devonfw.cobigen + gui + ${project.groupId} core-externalprocess-api @@ -52,6 +57,16 @@ google-java-format 1.10.0 + + org.openjfx + javafx-controls + ${javafx.version} + + + org.openjfx + javafx-fxml + ${javafx.version} + diff --git a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/CobiGenCommand.java b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/CobiGenCommand.java index 785687e380..e58e97f9a1 100644 --- a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/CobiGenCommand.java +++ b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/CobiGenCommand.java @@ -11,7 +11,7 @@ @Command(description = MessagesConstants.WELCOME_MESSAGE, name = "cobigen", aliases = { "cg" }, mixinStandardHelpOptions = true, subcommands = { GenerateCommand.class, UpdateCommand.class, -AdaptTemplatesCommand.class }, versionProvider = CobiGenVersionProvider.class) +AdaptTemplatesCommand.class, ManageCommand.class }, versionProvider = CobiGenVersionProvider.class) public class CobiGenCommand implements Runnable { @Override diff --git a/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/ManageCommand.java b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/ManageCommand.java new file mode 100644 index 0000000000..15fc2717cb --- /dev/null +++ b/cobigen-cli/cli/src/main/java/com/devonfw/cobigen/cli/commands/ManageCommand.java @@ -0,0 +1,44 @@ +package com.devonfw.cobigen.cli.commands; + +import java.util.concurrent.TimeUnit; + +import com.devonfw.cobigen.gui.AppLauncher; + +import picocli.CommandLine.Command; + +/** + * This class handles the manage template sets command + */ +@Command(description = "Opens GUI for Template Set Management", name = "manage", aliases = { +"m" }, mixinStandardHelpOptions = true) +public class ManageCommand extends CommandCommons { + + public AppLauncher launcher; + + /** + * Constructor needed for Picocli + */ + public ManageCommand() { + + super(); + } + + @Override + public synchronized Integer doAction() throws Exception { + + System.out.println("You just called the GUI"); + this.launcher = new AppLauncher(); + try { + wait(1337); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + while (this.launcher.app.window.isShowing()) { + TimeUnit.SECONDS.sleep(1); + } + + return 0; + } + +} diff --git a/cobigen-eclipse/cobigen-eclipse-feature/pom.xml b/cobigen-eclipse/cobigen-eclipse-feature/pom.xml index 01e23da9bd..706e825c4a 100644 --- a/cobigen-eclipse/cobigen-eclipse-feature/pom.xml +++ b/cobigen-eclipse/cobigen-eclipse-feature/pom.xml @@ -11,4 +11,9 @@ eclipse-parent ${revision} + + + false + + diff --git a/cobigen-eclipse/cobigen-eclipse-test/pom.xml b/cobigen-eclipse/cobigen-eclipse-test/pom.xml index 8fc4f9cf42..7feeaf8fd4 100644 --- a/cobigen-eclipse/cobigen-eclipse-test/pom.xml +++ b/cobigen-eclipse/cobigen-eclipse-test/pom.xml @@ -12,7 +12,6 @@ ${surefireArgLineIntegration} -Xms512m -Xmx2048m -XX:+DisableExplicitGC - true @@ -24,6 +23,10 @@ com.devonfw.cobigen core-api + + com.devonfw.cobigen + gui + ch.qos.logback logback-classic diff --git a/cobigen-eclipse/cobigen-eclipse-test/src/main/java/com/devonfw/cobigen/eclipse/test/OpenGUITest.java b/cobigen-eclipse/cobigen-eclipse-test/src/main/java/com/devonfw/cobigen/eclipse/test/OpenGUITest.java new file mode 100644 index 0000000000..bea75c98c4 --- /dev/null +++ b/cobigen-eclipse/cobigen-eclipse-test/src/main/java/com/devonfw/cobigen/eclipse/test/OpenGUITest.java @@ -0,0 +1,59 @@ +package com.devonfw.cobigen.eclipse.test; + +import java.io.File; + +import org.apache.commons.io.FileUtils; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.devonfw.cobigen.eclipse.test.common.SystemTest; +import com.devonfw.cobigen.eclipse.test.common.utils.EclipseCobiGenUtils; +import com.devonfw.cobigen.eclipse.test.common.utils.EclipseUtils; + +/** + * Class for testing Manage Template Sets with a click on the Home Button + * + */ +@RunWith(SWTBotJunit4ClassRunner.class) +public class OpenGUITest extends SystemTest { + + /** Root path of the Test Resources */ + private static final String resourcesRootPath = "src/main/resources/OpenAPITest/"; + + /** + * Setup workbench appropriately for tests + * + * @throws Exception test fails + */ + @BeforeClass + public static void setupClass() throws Exception { + + EclipseUtils.cleanWorkspace(bot, true); + } + + /** + * Testing to open the Template Set Management GUI and clicking Home Button + * + * @throws Exception test fails + */ + @Test + public void testOpenTemplateSetManagementGUI() throws Exception { + + // copy sample project to external location and import it into the workspace + String testProjName = "ExtTestProj"; + IJavaProject project = this.tmpMavenProjectRule.createProject(testProjName); + FileUtils.copyFile(new File(resourcesRootPath + "input/adapt-templates.yml"), + project.getUnderlyingResource().getLocation().append("adapt-templates.yml").toFile()); + project.getProject().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); + this.tmpMavenProjectRule.updateProject(); + + // open GUI + EclipseCobiGenUtils.runAndCaptureManageTemplateSets(bot); + } + +} diff --git a/cobigen-eclipse/cobigen-eclipse-test/src/main/java/com/devonfw/cobigen/eclipse/test/common/utils/EclipseCobiGenUtils.java b/cobigen-eclipse/cobigen-eclipse-test/src/main/java/com/devonfw/cobigen/eclipse/test/common/utils/EclipseCobiGenUtils.java index 992b7cbb56..0c1ad313e4 100644 --- a/cobigen-eclipse/cobigen-eclipse-test/src/main/java/com/devonfw/cobigen/eclipse/test/common/utils/EclipseCobiGenUtils.java +++ b/cobigen-eclipse/cobigen-eclipse-test/src/main/java/com/devonfw/cobigen/eclipse/test/common/utils/EclipseCobiGenUtils.java @@ -402,6 +402,28 @@ public static void runAndCaptureAdaptTemplates(SWTWorkbenchBot bot) throws Excep informationDialog.bot().button("Ok").click(); } + /** + * Checks the CobiGen Manage Template Sets and takes screenshots of it. + * + * @param bot to process the Manage Template Sets command + * @throws Exception test fails + */ + public static void runAndCaptureManageTemplateSets(SWTWorkbenchBot bot) throws Exception { + + ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor()); + bot.waitUntil(new AllJobsAreFinished(), DEFAULT_TIMEOUT); // build might take some time + + SWTBotView view = bot.viewById(JavaUI.ID_PACKAGES); + view.bot().tree().contextMenu("CobiGen").menu("Manage Template Sets...").click(); + + // TODO + // bot.waitUntil(new AnyShellIsActive("Template Set Manager"), DEFAULT_TIMEOUT); + // takeScreenshot(bot, "Template Set Manager"); + // SWTBotShell gui = bot.shell("Template Set Manager"); + // gui.bot().button("#homeButton").click(); + + } + /** * Takes a screenshot (*.jpeg) of the current screen encoding test method and class and appends the given identifier * to the file name diff --git a/cobigen-eclipse/cobigen-eclipse/build.properties b/cobigen-eclipse/cobigen-eclipse/build.properties index 4415ea671c..82304223d5 100644 --- a/cobigen-eclipse/cobigen-eclipse/build.properties +++ b/cobigen-eclipse/cobigen-eclipse/build.properties @@ -53,4 +53,13 @@ bin.includes = .,\ lib/plexus-utils.jar,\ lib/slf4j-api.jar,\ lib/txw2.jar,\ - lib/zt-exec.jar + lib/zt-exec.jar,\ + lib/gui.jar,\ + lib/javafx-base.jar,\ + lib/javafx-base-win.jar,\ + lib/javafx-controls.jar,\ + lib/javafx-controls-win.jar,\ + lib/javafx-fxml.jar,\ + lib/javafx-fxml-win.jar,\ + lib/javafx-graphics.jar,\ + lib/javafx-graphics-win.jar diff --git a/cobigen-eclipse/cobigen-eclipse/plugin.xml b/cobigen-eclipse/cobigen-eclipse/plugin.xml index 647a2dbdb7..d8d6e14612 100644 --- a/cobigen-eclipse/cobigen-eclipse/plugin.xml +++ b/cobigen-eclipse/cobigen-eclipse/plugin.xml @@ -19,6 +19,10 @@ id="com.devonfw.cobigen.eclipseplugin.adapt_template" name="Adapt Template"> + + @@ -38,6 +42,10 @@ class="com.devonfw.cobigen.eclipse.workbenchcontrol.handler.AdaptTemplatesHandler" commandId="com.devonfw.cobigen.eclipseplugin.adapt_template"> + + @@ -70,6 +78,11 @@ label="Adapt Templates..." style="push"> + + + + + + diff --git a/cobigen-eclipse/cobigen-eclipse/pom.xml b/cobigen-eclipse/cobigen-eclipse/pom.xml index 97648bc5b6..eff89f5c1a 100644 --- a/cobigen-eclipse/cobigen-eclipse/pom.xml +++ b/cobigen-eclipse/cobigen-eclipse/pom.xml @@ -24,6 +24,10 @@ com.devonfw.cobigen core-externalprocess-api + + com.devonfw.cobigen + gui + com.devonfw.cobigen javaplugin-model diff --git a/cobigen-eclipse/cobigen-eclipse/src/com/devonfw/cobigen/eclipse/workbenchcontrol/handler/ManageTemplateSetsHandler.java b/cobigen-eclipse/cobigen-eclipse/src/com/devonfw/cobigen/eclipse/workbenchcontrol/handler/ManageTemplateSetsHandler.java new file mode 100644 index 0000000000..aa88164524 --- /dev/null +++ b/cobigen-eclipse/cobigen-eclipse/src/com/devonfw/cobigen/eclipse/workbenchcontrol/handler/ManageTemplateSetsHandler.java @@ -0,0 +1,52 @@ +package com.devonfw.cobigen.eclipse.workbenchcontrol.handler; + +import java.util.concurrent.TimeUnit; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.cobigen.gui.AppLauncher; + +/** + * Handler for the Package-Explorer Event + * + */ +public class ManageTemplateSetsHandler extends AbstractHandler { + + /** + * Assigning logger to ManageTemplateSetsHandler + */ + private static final Logger LOG = LoggerFactory.getLogger(ManageTemplateSetsHandler.class); + + /** + * Launcher for GUI + */ + public AppLauncher launcher; + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + System.out.println("You just called the GUI"); + this.launcher = new AppLauncher(); + try { + wait(1337); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + while (this.launcher.app.window.isShowing()) { + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + return null; + + } + +} diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java index ce21d5eafc..70d56141b0 100644 --- a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java @@ -134,4 +134,6 @@ public class ConfigurationConstants { */ public static final String CONFIG_PROPERTY_TEMPLATE_SETS_DEFAULT_VERSION = "2021.12.007"; + public static final String TEMPLATE_SET_ARTIFACT_CACHE_FOLDER = "template-set-list"; + } diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenCoordinate.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenCoordinate.java index 96f51f2c43..6d19bf3312 100644 --- a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenCoordinate.java +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenCoordinate.java @@ -1,11 +1,12 @@ package com.devonfw.cobigen.api.util; +import java.util.Arrays; import java.util.Objects; /** * This MavenCoordinate class is just a dataholder with maven coordinates. */ -public class MavenCoordinate { +public class MavenCoordinate implements Comparable { /** * the groupId of the maven artifact @@ -86,4 +87,22 @@ public boolean equals(Object obj) { && Objects.equals(this.version, other.version); } + @Override + public int compareTo(MavenCoordinate other) { + + if (!this.artifactId.equals(other.artifactId)) { + throw new ClassCastException("The artifactID of the comprarable should be the same"); + // TODO + } + int[] versionNumbersCurrent = Arrays.stream(this.version.split("\\.")).mapToInt(Integer::parseInt).toArray(); + int[] versionNumbersOther = Arrays.stream(other.getVersion().split("\\.")).mapToInt(Integer::parseInt).toArray(); + for (int i = 0; i < versionNumbersCurrent.length; i++) { + if (versionNumbersCurrent[i] > versionNumbersOther[i]) { + return 1; + } else if (versionNumbersCurrent[i] < versionNumbersOther[i]) + return -1; + } + return 0; + } + } diff --git a/cobigen/cobigen-core-api/src/test/java/com/devonfw/cobigen/api/TemplatesJarUtilTest.java b/cobigen/cobigen-core-api/src/test/java/com/devonfw/cobigen/api/TemplatesJarUtilTest.java new file mode 100644 index 0000000000..5e80f34f14 --- /dev/null +++ b/cobigen/cobigen-core-api/src/test/java/com/devonfw/cobigen/api/TemplatesJarUtilTest.java @@ -0,0 +1,40 @@ +package com.devonfw.cobigen.api; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.api.util.TemplatesJarUtil; + +public class TemplatesJarUtilTest { + /** + * Temp folder for test execution + */ + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + /** Testdata root path */ + private static final String testdataRoot = "src/test/resources/testdata/unittest/MavenUtilTest"; + + /** + * Tests to check if a correct cache will be validated right + * + * @throws Exception + */ + @Test + public void testDownloadFile() throws Exception { + + Path tempFolder = this.temp.newFolder(ConfigurationConstants.TEMPLATE_SETS_FOLDER).toPath(); + String test = TemplatesJarUtil.downloadJarFromURL( + "https://repo1.maven.org/maven2/com/devonfw/cobigen/templates-devon4j/2021.12.006/templates-devon4j-2021.12.006.pom", + tempFolder); + assertThat(Paths.get(test)).exists(); + + } +} diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ArtifactRetrieverUtil.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ArtifactRetrieverUtil.java new file mode 100644 index 0000000000..22f77f2112 --- /dev/null +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ArtifactRetrieverUtil.java @@ -0,0 +1,125 @@ +package com.devonfw.cobigen.impl.util; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.api.util.CobiGenPaths; +import com.devonfw.cobigen.api.util.TemplatesJarUtil; +import com.devonfw.cobigen.impl.config.entity.io.TemplateSetConfiguration; +import com.devonfw.cobigen.impl.config.reader.TemplateSetConfigurationReader; + +public class ArtifactRetrieverUtil { + + private static final Logger LOG = LoggerFactory.getLogger(ArtifactRetrieverUtil.class); + + /** Path to artifact cache folder **/ + private static Path artifactCachePath = CobiGenPaths.getTemplateSetsFolderPath() + .resolve(ConfigurationConstants.TEMPLATE_SET_ARTIFACT_CACHE_FOLDER); + + /** + * Downloads template set artifacts from given URLs + * + * @param artifactUrls List of URLs + * @return List of artifact Paths + */ + public static List downloadArtifactsFromUrls(List artifactUrls) { + + List artifactPaths = new ArrayList<>(); + for (URL url : artifactUrls) { + artifactPaths.add(Paths.get(TemplatesJarUtil.downloadJarFromURL(url.toString(), artifactCachePath))); + + } + + return artifactPaths; + } + + /** + * Retrieves the artifact cache path + * + * @return Path to artifact cache folder + */ + public static Path retrieveArtifactCachePath() { + + Path artifactCacheFolder = CobiGenPaths.getTemplateSetsFolderPath() + .resolve(ConfigurationConstants.TEMPLATE_SET_ARTIFACT_CACHE_FOLDER); + return artifactCacheFolder; + } + + /** + * Checks is a directory is empty + * + * @param path directory to check + * @return true if empty, false if not + * @throws IOException + */ + private static boolean isEmpty(Path path) throws IOException { + + if (Files.isDirectory(path)) { + try (DirectoryStream directory = Files.newDirectoryStream(path)) { + return !directory.iterator().hasNext(); + } catch (IOException e) { + LOG.debug("An error occurred while checking if the directory {} was empty", path, e); + } + } + + return false; + } + + /** + * Retrieves a list of {@link TemplateSetConfiguration} from the template set artifact cache + * + * @param cachedArtifacts List of template set artifact paths + * + * @return List of {@link TemplateSetConfiguration} + */ + public static List retrieveArtifactsFromCache(List cachedArtifacts) { + + List templateSetConfigurations = new ArrayList<>(); + + if (cachedArtifacts == null) { + + Path artifactCacheFolder = retrieveArtifactCachePath(); + try { + if (!Files.exists(artifactCacheFolder) || isEmpty(artifactCacheFolder)) { + return null; + } + } catch (IOException e) { + LOG.error("An error occurred while checking the artifact cache directory {}", artifactCacheFolder, e); + return null; + } + + List artfactList = Arrays.asList(artifactCacheFolder.toFile().listFiles()); + for (File file : artfactList) { + TemplateSetConfigurationReader reader = new TemplateSetConfigurationReader(file.toPath()); + reader.readConfiguration(file.toPath()); + + TemplateSetConfiguration templateSetConfiguration = reader.getTemplateSetConfiguration(); + templateSetConfigurations.add(templateSetConfiguration); + } + return templateSetConfigurations; + } + + for (Path file : cachedArtifacts) { + TemplateSetConfigurationReader reader = new TemplateSetConfigurationReader(file); + reader.readConfiguration(file); + + TemplateSetConfiguration templateSetConfiguration = reader.getTemplateSetConfiguration(); + templateSetConfigurations.add(templateSetConfiguration); + } + + return templateSetConfigurations; + + } +} diff --git a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/templates/TemplateJarDownloaderTest.java b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/templates/TemplateJarDownloaderTest.java index 87ed5329af..ebbfa21dc1 100644 --- a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/templates/TemplateJarDownloaderTest.java +++ b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/templates/TemplateJarDownloaderTest.java @@ -149,7 +149,7 @@ public void testDownloadTemplatesWithLATEST() { public void testDownloadTemplates() throws Exception { // preparation - File adapted = this.tempFolder.newFolder("templateLocation/adapted"); + File adapted = this.tempFolder.newFolder("templateLocation", "adapted"); this.mavenCoordinatesList.add(new MavenCoordinate("com.group", "artifact-id", "1.0")); this.mavenCoordinatesList.add(new MavenCoordinate("some.group", "some-artifact", "2.01")); this.mavenCoordinatesList.add(createMavenCoordinateForDevon4jTemplates(null)); @@ -173,7 +173,7 @@ public void testDownloadTemplates() throws Exception { public void testDownloadTemplatesAlreadyAdapted() throws Exception { // preparation - File adapted = this.tempFolder.newFolder("templateLocation/adapted"); + File adapted = this.tempFolder.newFolder("templateLocation", "adapted"); this.mavenCoordinatesList.add(new MavenCoordinate("com.group", "artifact-id", "1.0")); this.mavenCoordinatesList.add(new MavenCoordinate("some.group", "some-artifact", "2.01")); this.mavenCoordinatesList.add(new MavenCoordinate("com.com", "app-app", "87")); diff --git a/cobigen/core-artifact-retriever/pom.xml b/cobigen/core-artifact-retriever/pom.xml index e25d97998f..e22bb295bd 100644 --- a/cobigen/core-artifact-retriever/pom.xml +++ b/cobigen/core-artifact-retriever/pom.xml @@ -77,5 +77,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/x core-api + + \ No newline at end of file diff --git a/cobigen/core-artifact-retriever/src/main/java/com/devonfw/cobigen/retriever/ArtifactRetriever.java b/cobigen/core-artifact-retriever/src/main/java/com/devonfw/cobigen/retriever/ArtifactRetriever.java index 170d6ed1b7..a3363fd6bb 100644 --- a/cobigen/core-artifact-retriever/src/main/java/com/devonfw/cobigen/retriever/ArtifactRetriever.java +++ b/cobigen/core-artifact-retriever/src/main/java/com/devonfw/cobigen/retriever/ArtifactRetriever.java @@ -65,7 +65,7 @@ public static List retrieveTemplateSetJarDownloadURLs(List group * @return list of maven artifact download URLs * */ - protected static List retrieveTemplateSetXmlDownloadLinks(List groupIdsList, String mavenSettings) { + public static List retrieveTemplateSetXmlDownloadLinks(List groupIdsList, String mavenSettings) { List downloadLinks = new ArrayList<>(); @@ -99,9 +99,7 @@ protected static List retrieveTemplateSetXmlDownloadLinks(List grou downloadLinks.addAll( retrieveArtifactsFromRepository(groupIdsList, null, null, new ArrayList())); } - return downloadLinks; - } /** diff --git a/cobigen/gui/pom.xml b/cobigen/gui/pom.xml new file mode 100644 index 0000000000..6cb4ff1acf --- /dev/null +++ b/cobigen/gui/pom.xml @@ -0,0 +1,115 @@ + + 4.0.0 + gui + jar + + + com.devonfw.cobigen + core-parent + ${revision} + + + + false + UTF-8 + 11 + 11 + 19 + 0.0.6 + + + + + org.openjfx + javafx-controls + ${javafx.version} + + + org.openjfx + javafx-fxml + ${javafx.version} + + + junit + junit + 4.13.1 + + + org.testfx + testfx-core + 4.0.16-alpha + test + + + org.testfx + testfx-junit + 4.0.15-alpha + test + + + org.assertj + assertj-core + 3.13.2 + test + + + org.kordamp.ikonli + ikonli-javafx + 11.3.5 + + + org.kordamp.ikonli + ikonli-materialdesign-pack + 11.3.5 + + + com.devonfw.cobigen + core-artifact-retriever + ${revision} + + + com.devonfw.cobigen + core + ${revision} + + + com.github.stefanbirkner + system-lambda + 1.2.0 + test + + + com.devonfw.cobigen + core-test + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.release} + + + + org.openjfx + javafx-maven-plugin + ${javafx.maven.plugin.version} + + com.devonfw.cobigen.gui.App + + + + org.apache.maven.plugins + maven-surefire-plugin + + + false + + + + + \ No newline at end of file diff --git a/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/App.java b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/App.java new file mode 100644 index 0000000000..b499cc3b84 --- /dev/null +++ b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/App.java @@ -0,0 +1,91 @@ +package com.devonfw.cobigen.gui; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.image.Image; +import javafx.stage.Stage; +import javafx.stage.StageStyle; + +/** + * TODO nneuhaus This type ... + * + */ +public class App extends Application { + + /** + * latch for waiting for the app + */ + public static final CountDownLatch latch = new CountDownLatch(1); + + /** + * The app itself + */ + public static App app = null; + + /** + * The scene to set in the window + */ + private static Scene scene; + + /** + * The window to show in the app + */ + public Stage window; + + /** + * @return the app when it is ready + */ + public static App waitForApp() { + + try { + latch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return app; + } + + /** + * Sets the given app as the general app + * + * @param app0 gets set as the app + */ + public static void setApp(App app0) { + + app = app0; + latch.countDown(); + } + + /** + * The constructor. + */ + public App() { + + setApp(this); + } + + @Override + public void start(Stage primaryStage) throws IOException { + + this.window = new Stage(); + Parent root = FXMLLoader.load(getClass().getResource("fxml/Primary.fxml")); + + App.scene = new Scene(root); + App.scene.getStylesheets().add(getClass().getResource("styles.css").toExternalForm()); + + Image image = new Image(App.class.getResource("icons/devon-icon.jpg").toExternalForm()); + this.window.setTitle("Template Set Manager"); + this.window.getIcons().add(image); + this.window.initStyle(StageStyle.TRANSPARENT); + this.window.setResizable(true); + + this.window.setScene(App.scene); + this.window.showAndWait(); + } + +} diff --git a/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/AppLauncher.java b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/AppLauncher.java new file mode 100644 index 0000000000..f2fcf3ecdd --- /dev/null +++ b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/AppLauncher.java @@ -0,0 +1,35 @@ +package com.devonfw.cobigen.gui; + +/** + * TODO nneuhaus This type ... + * + */ +public class AppLauncher { + + public App app; + + public AppLauncher() { + + new Thread() { + @Override + public void run() { + + javafx.application.Application.launch(App.class); + } + }.start(); + this.app = App.waitForApp(); + } + + public static void main(String[] args) { + + new Thread() { + @Override + public void run() { + + javafx.application.Application.launch(App.class); + } + }.start(); + App app = App.waitForApp(); + } + +} diff --git a/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/Controller.java b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/Controller.java new file mode 100644 index 0000000000..a9272bfca3 --- /dev/null +++ b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/Controller.java @@ -0,0 +1,200 @@ +package com.devonfw.cobigen.gui; + +import java.io.IOException; +import java.net.URL; +import java.util.List; +import java.util.ResourceBundle; + +import com.devonfw.cobigen.gui.controllers.DetailsController; +import com.devonfw.cobigen.gui.controllers.HomeController; +import com.devonfw.cobigen.gui.controllers.MenuController; +import com.devonfw.cobigen.gui.services.TreeViewBuilder; +import com.devonfw.cobigen.impl.config.entity.io.Increment; +import com.devonfw.cobigen.impl.config.entity.io.TemplateSetConfiguration; + +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.Parent; +import javafx.scene.control.Button; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Pane; +import javafx.stage.Stage; + +/** + * Controller for the Template Set Management GUI + */ +public class Controller implements Initializable { + /* + * home Controller to show home page + */ + @FXML + private Parent home; + + /* + * Details Controller for template set details + */ + @FXML + private Parent details; + + @FXML + public MenuController menuController; + + @FXML + private HomeController homeController; + + @FXML + public DetailsController detailsController; + + // deals with menu.fxml + @FXML + private AnchorPane leftPane; + + @FXML + private AnchorPane searchPane; + + @FXML + private AnchorPane rightPane; + + @FXML + private AnchorPane detailsPane; + + // top bit of the gui + @FXML + private Pane topPane; + + @FXML + private Button closeButton; + + @FXML + private Button minButton; + + @FXML + private Button minMaxButton; + + private double xOffset = 0; + + private double yOffset = 0; + + /** + * Initial View + */ + @Override + public void initialize(URL arg0, ResourceBundle arg1) { + + this.menuController.injectController(this); + } + + /** + * @param actionEvent + * @throws IOException + */ + @FXML + public void loadHome(javafx.event.ActionEvent actionEvent) throws IOException { + + this.details.setVisible(false); + this.home.setVisible(true); + this.menuController.clearSearchResults(); + this.menuController.searchResultsView.getSelectionModel().clearSelection(); + } + + /** + * Load increment from selected template-set from observable list + * + * @throws IOException + */ + public void loadDetails() throws IOException { + + // selected from observable list + TemplateSetConfiguration selectedItem = this.menuController.searchResultsView.getSelectionModel().getSelectedItem(); + // changing visibility between scenes + if (selectedItem == null) { + this.home.setVisible(true); + this.details.setVisible(false); + } else { + this.home.setVisible(false); + this.details.setVisible(true); + + // Getting the tree view of increments of selected template set + + // Extract all increments from selected templateSet in list + List templatesetIncrements = selectedItem.getTemplatesConfiguration().getIncrements().getIncrement(); + + // shows the tree view of increments of selected template set + this.detailsController.showTreeView(TreeViewBuilder.buildTreeView(templatesetIncrements)); + + // TODO + this.detailsController.showName(selectedItem.getVersion().toString()); + + // retrieving template-Set selected and pass it to details Controller + this.detailsController + .setTemplateSet(this.menuController.searchResultsView.getSelectionModel().getSelectedItem()); + + // updates the install button text + this.detailsController.updateTemplateSetInstallStatus(); + + } + + } + + /** + * @param event: click on the x Button + */ + @FXML + protected void handleCloseAction(ActionEvent event) { + + // get the current stage + Stage stage = (Stage) this.closeButton.getScene().getWindow(); + // close the window + stage.close(); + } + + /** + * @param event : click on the Button to switch window view + */ + @FXML + protected void handleMinMaxAction(ActionEvent event) { + + // get the current stage + Stage stage = (Stage) this.minMaxButton.getScene().getWindow(); + // if window is full screen, make it smaller + // if it is a small window, make it full screen + if (stage.isMaximized()) { + stage.setMaximized(false); + } else { + stage.setMaximized(true); + } + + } + + /** + * @param event : click on the minimize Button + */ + @FXML + protected void handleMinAction(ActionEvent event) { + + // this minimizes the window, can be reopened by clicking in the icon in the task bar + // TODO: fix animation if possible? + Stage stage = (Stage) this.minButton.getScene().getWindow(); + stage.setIconified(true); + + } + + @FXML + protected void handleClickAction(MouseEvent event) { + + Stage stage = (Stage) this.topPane.getScene().getWindow(); + this.xOffset = stage.getX() - event.getScreenX(); + this.yOffset = stage.getY() - event.getScreenY(); + } + + @FXML + protected void handleMovementAction(MouseEvent event) { + + Stage stage = (Stage) this.topPane.getScene().getWindow(); + + stage.setX(event.getScreenX() + this.xOffset); + stage.setY(event.getScreenY() + this.yOffset); + } +} diff --git a/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/controllers/DetailsController.java b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/controllers/DetailsController.java new file mode 100644 index 0000000000..50558dfa92 --- /dev/null +++ b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/controllers/DetailsController.java @@ -0,0 +1,215 @@ +package com.devonfw.cobigen.gui.controllers; + +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.ResourceBundle; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.api.util.CobiGenPaths; +import com.devonfw.cobigen.api.util.MavenCoordinate; +import com.devonfw.cobigen.api.util.TemplatesJarUtil; +import com.devonfw.cobigen.impl.config.entity.io.TemplateSetConfiguration; +import com.devonfw.cobigen.retriever.ArtifactRetriever; + +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TreeView; +import javafx.scene.layout.AnchorPane; +import javafx.scene.text.Text; + +/** + * TODO nneuhaus This type ... + * + */ +public class DetailsController implements Initializable { + + private static final Logger LOG = LoggerFactory.getLogger(ArtifactRetriever.class); + + // TODO: getIncrements() + private List INCREMENTS = new ArrayList<>(); + + private TemplateSetConfiguration templateSet; + + @FXML + Label titleLabel; + + @FXML + Text descriptionText; + + @FXML + Button installButton; + + @FXML + AnchorPane treeViewPane; + + @Override + public void initialize(URL location, ResourceBundle resources) { + + // increment section of the gui + showVersion(); + // showTreeView(TreeViewBuilder.buildTreeView(TreeViewBuilder.transformIncrementsToArray(this.INCREMENTS))); + + } + + /** + * Sets text of install button to Installed + */ + public void updateTemplateSetInstallStatus() { + + Path templateSetPath = retrieveJarPathFromTemplateSet(); + if (Files.exists(templateSetPath)) { + this.installButton.setText("Installed"); + } else { + this.installButton.setText("Install"); + } + + } + + /** + * returns an instance of selected template Set to be operated on + * + * @return templateSet + */ + public TemplateSetConfiguration getTemplateSet() { + + return this.templateSet; + } + + /** + * Set the instance of selected template Set + * + * @param templateSet new value of {@link #gettemplateSet}. + */ + public void setTemplateSet(TemplateSetConfiguration templateSet) { + + this.templateSet = templateSet; + } + + /** + * + */ + public void showName(String name) { + + this.titleLabel.setText(name); + + } + + /** + * + */ + private void showVersion() { + + // is it the version used in templateSet or the snapshot version? + // TODO: getVersion() + + } + + /** + * @param treeView + */ + public void showTreeView(TreeView treeView) { + + treeView.setId("treeView"); + AnchorPane.setTopAnchor(treeView, 0.0); + AnchorPane.setRightAnchor(treeView, 0.0); + AnchorPane.setBottomAnchor(treeView, 0.0); + AnchorPane.setLeftAnchor(treeView, 0.0); + this.treeViewPane.getChildren().add(treeView); + } + + /** + * Retrieves the jar file path from the selected template set + * + * @return Path to template set jar + */ + private Path retrieveJarPathFromTemplateSet() { + + // Retrieve template set name information from trigger + String triggerName = this.templateSet.getContextConfiguration().getTrigger().get(0).getId(); + String mavenArtfifactId = triggerName.replace("_", "-"); + String templateSetVersion = this.templateSet.getVersion().toString(); + Path templateSetsPath = CobiGenPaths.getTemplateSetsFolderPath(); + + // Adjust file name + String FileName = mavenArtfifactId + "-" + templateSetVersion + ".jar"; + Path jarFilePath = templateSetsPath.resolve(ConfigurationConstants.DOWNLOADED_FOLDER).resolve(FileName); + + return jarFilePath; + } + + /** + * Installs a template set into the template-sets/downloaded folder + * + * @param actionEvent the action event + */ + @FXML + public void installTemplateSet(javafx.event.ActionEvent actionEvent) { + + // Retrieve template set name information from trigger + String triggerName = this.templateSet.getContextConfiguration().getTrigger().get(0).getId(); + String mavenArtfifactId = triggerName.replace("_", "-"); + String templateSetVersion = this.templateSet.getVersion().toString(); + + // Adjust file name + String FileName = mavenArtfifactId + "-" + templateSetVersion + ".jar"; + + Path templateSetsPath = CobiGenPaths.getTemplateSetsFolderPath(); + + // prepare MavenCoordinate list for download + MavenCoordinate mavenCoordinate = new MavenCoordinate( + ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_DEFAULT_GROUPID, mavenArtfifactId, templateSetVersion); + List mavenCoordinateList = new ArrayList<>(); + mavenCoordinateList.add(mavenCoordinate); + + Path expectedJarFilePath = templateSetsPath.resolve(ConfigurationConstants.DOWNLOADED_FOLDER).resolve(FileName); + + if (!Files.exists(expectedJarFilePath)) { + // Download template set class file into downloaded folder + TemplatesJarUtil.downloadTemplatesByMavenCoordinates( + templateSetsPath.resolve(ConfigurationConstants.DOWNLOADED_FOLDER), mavenCoordinateList); + // TODO: update installButton title to Installed and save this state + updateTemplateSetInstallStatus(); + } else { + // Alert window if the file is already installed + Alert alert = new Alert(AlertType.CONFIRMATION); + alert.setTitle("Confirmation"); + alert.setHeaderText("The selected template-set is already installed!"); + alert.show(); + } + } + + /** + * @param actionEvent + */ + @FXML + public void updateTemplateSet(javafx.event.ActionEvent actionEvent) { + + // what model is previous and whats the new one + // new version rein packen + + // TODO + } + + /** + * @param actionEvent + */ + @FXML + public void uninstallTemplateSet(javafx.event.ActionEvent actionEvent) { + + // what is referred to by the word uninstall. + // Delete template set from user ordenr + + // TODO + } + +} diff --git a/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/controllers/HomeController.java b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/controllers/HomeController.java new file mode 100644 index 0000000000..b3f491848e --- /dev/null +++ b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/controllers/HomeController.java @@ -0,0 +1,85 @@ +package com.devonfw.cobigen.gui.controllers; + +import java.awt.Desktop; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ResourceBundle; + +import com.devonfw.cobigen.gui.App; + +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.Scene; +import javafx.scene.control.MenuButton; +import javafx.scene.layout.AnchorPane; + +/** + * TODO nneuhaus This type ... + * + */ +public class HomeController implements Initializable { + + @FXML + AnchorPane homePane; + + @FXML + AnchorPane treeViewPane; + + @FXML + MenuButton settings; + + private String[] EXAMPLE_LIST = { "Title of Increment 1", "Description of Increment 1", "Title of Increment 2", + "Description of Increment 2", "Title of Increment 3", "Description of Increment 3" }; + + private String lightTheme = App.class.getResource("styles.css").toExternalForm(); + + private String darkTheme = App.class.getResource("dark_theme.css").toExternalForm(); + + @Override + public void initialize(URL location, ResourceBundle resources) { + + // Increment increment1 = new Increment(); + // increment1.setName("Title of Increment 1"); + // increment1.setDescription("Description of Increment 1"); + // Increment increment2 = new Increment(); + // increment2.setName("Title of Increment 2"); + // increment2.setDescription("Description of Increment 2"); + // Increment increment3 = new Increment(); + // increment3.setName("Title of Increment 3"); + // increment3.setDescription("Description of Increment 3"); + // // Build the tree view + // TreeView treeView = TreeViewBuilder.buildTreeView(this.EXAMPLE_LIST); + // treeView.setId("treeView"); + // AnchorPane.setTopAnchor(treeView, 0.0); + // AnchorPane.setRightAnchor(treeView, 0.0); + // AnchorPane.setBottomAnchor(treeView, 0.0); + // AnchorPane.setLeftAnchor(treeView, 0.0); + // this.treeViewPane.getChildren().add(treeView); + } + + /** + * @param actionEvent + * @throws IOException + * @throws URISyntaxException + */ + @FXML + public void openWiki(javafx.event.ActionEvent actionEvent) throws IOException, URISyntaxException { + + Desktop.getDesktop().browse(new URI("https://github.com/devonfw/cobigen/wiki")); + } + + public void changeTheme(javafx.event.ActionEvent actionEvent) throws IOException { + + Scene scene = this.treeViewPane.getScene(); + + if (scene.getStylesheets().contains(this.lightTheme)) { + scene.getStylesheets().remove(this.lightTheme); + scene.getStylesheets().add(this.darkTheme); + } else { + scene.getStylesheets().remove(this.darkTheme); + scene.getStylesheets().add(this.lightTheme); + } + } +} diff --git a/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/controllers/MenuController.java b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/controllers/MenuController.java new file mode 100644 index 0000000000..45523bfe91 --- /dev/null +++ b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/controllers/MenuController.java @@ -0,0 +1,253 @@ +package com.devonfw.cobigen.gui.controllers; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.ListIterator; +import java.util.ResourceBundle; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.api.util.CobiGenPaths; +import com.devonfw.cobigen.api.util.MavenCoordinate; +import com.devonfw.cobigen.api.util.MavenUtil; +import com.devonfw.cobigen.gui.Controller; +import com.devonfw.cobigen.gui.model.TemplateSetModel; +import com.devonfw.cobigen.gui.services.TemplateSetCell; +import com.devonfw.cobigen.impl.config.entity.io.TemplateSetConfiguration; +import com.devonfw.cobigen.impl.util.ArtifactRetrieverUtil; +import com.devonfw.cobigen.retriever.ArtifactRetriever; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.collections.transformation.FilteredList; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.Button; +import javafx.scene.control.ListView; +import javafx.scene.control.TextField; + +/** + * TODO nneuhaus This type ... + * + */ +public class MenuController implements Initializable { + + /** Logger instance */ + private static final Logger LOG = LoggerFactory.getLogger(MenuController.class); + + @FXML + private Controller controller; + + @FXML + public Button homeButton; + + @FXML + public TextField searchBar; + + @FXML + public Button clearSearchResultsButton; + + @FXML + public Button goSearch; + + @FXML + public ListView searchResultsView; + + /** + * The constructor. + */ + public MenuController() { + + // Where do we need tags + // List tagsList = new ArrayList<>(); + // tagsList.addAll(templateSet.getTemplateSetConfiguration().getContextConfiguration().getTags().getTagsList()); + } + + /** + * Method to get a reference to the main controller + */ + public void injectController(Controller controller) { + + this.controller = controller; + } + + /** + * Initial method when controller gets activated + */ + @Override + public void initialize(URL location, ResourceBundle resources) { + + // the line below sets up the template set cells in observable list + this.searchResultsView.setCellFactory(resultsView -> new TemplateSetCell()); + + this.homeButton.setOnAction(event -> { + try { + this.controller.loadHome(event); + } catch (IOException e) { + LOG.error("An error occurred while loading the home page", e); + } + }); + + Path artifactCachePath = CobiGenPaths.getTemplateSetsFolderPath() + .resolve(ConfigurationConstants.TEMPLATE_SET_ARTIFACT_CACHE_FOLDER); + List cachedArtifacts = new ArrayList<>(); + if (!Files.exists(artifactCachePath)) { + try { + Files.createDirectory(artifactCachePath); + } catch (IOException e) { + LOG.error("An error occurred while creating the artifact cache directory", e); + } + } else { + + for (File artifact : Arrays.asList(artifactCachePath.toFile().listFiles())) { + cachedArtifacts.add(artifact.toPath()); + } + } + + // TODO: read CobiGen properties + refresh(); + + // Load increments of selected template set + // call back functions + this.searchResultsView.setOnMouseClicked(event -> { + + try { + MenuController.this.controller.loadDetails(); + } catch (IOException e) { + LOG.error("An error occurred while loading the details page", e); + } + + }); + + // Initialize filtered List + + ObservableList listCopy = TemplateSetModel.getInstance().getTemplateSetObservableList(); + FilteredList filteredData = new FilteredList<>( + TemplateSetModel.getInstance().getTemplateSetObservableList(), b -> true); + + // look after the searched text in search bar + this.searchBar.textProperty().addListener((observable, oldValue, newValue) -> { + filteredData.setPredicate(templateSets -> { + // if no search value, then display all records or whatever records it currently has, no changes + if (newValue.isEmpty() || newValue.isBlank() || newValue == null) { + return true; + } + + String searchKeyword = newValue.toLowerCase(); + // found a match in the name + // if (templateSets.getName().toLowerCase().indexOf(searchKeyword) > -1) { + // return true; + // } + // add more if statements of this form + // if more search relevant attributes are added to the TemplateSet Class! + + // else + return false; + }); + + this.searchResultsView.setItems(filteredData); + + }); + + } + + /** + * Update list view of template sets and their installation status + */ + @FXML + public void refresh() { + // check if clear the list is needed + + Path artifactCachePath = CobiGenPaths.getTemplateSetsFolderPath() + .resolve(ConfigurationConstants.TEMPLATE_SET_ARTIFACT_CACHE_FOLDER); + List cachedArtifacts = new ArrayList<>(); + if (!Files.exists(artifactCachePath)) { + try { + Files.createDirectory(artifactCachePath); + } catch (IOException e) { + LOG.error("An error occurred while creating the artifact cache directory", e); + } + } else { + + for (File artifact : Arrays.asList(artifactCachePath.toFile().listFiles())) { + cachedArtifacts.add(artifact.toPath()); + } + } + + // TODO: read CobiGen properties + List groupIds = Arrays.asList(ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_DEFAULT_GROUPID); + List urlList = ArtifactRetriever.retrieveTemplateSetXmlDownloadLinks(groupIds, + MavenUtil.determineMavenSettings()); + + // check for Update + // TODO error handling with replace all and maybe jar is corrupted just replace it + // also try to export this to other functions + List cachedMavenCoordinates = new ArrayList<>(); + for (Path p : cachedArtifacts) { + String version = p.getFileName().toString().replaceAll("-template-set.xml", "") + .replaceAll("^(([a-zA-z]+[\\w]-)+)", ""); + String artifactID = p.getFileName().toString().replaceAll("-template-set.xml", "").replaceAll("-" + version, ""); + cachedMavenCoordinates.add(new MavenCoordinate(null, artifactID, version)); + } + ListIterator iterator = urlList.listIterator(); + while (iterator.hasNext()) { + String maven = iterator.next().getFile().replaceAll("-template-set.xml", ""); + String version = maven.replaceAll("^(([a-zA-z]+[\\w]-)+)", ""); + String artifactID = maven.replaceAll("-" + version, ""); + MavenCoordinate repo = new MavenCoordinate(null, artifactID, version); + for (MavenCoordinate cached : cachedMavenCoordinates) { + if (cached.getArtifactId().equals(repo.getArtifactId())) { + int result = cached.compareTo(repo); + if (result <= 0) { + // no download needed + iterator.remove(); + } else { + // download needed ccan be removed, leave it for debugging pruposes + } + } + } + } + + List downloadedArtifacts = ArtifactRetrieverUtil.downloadArtifactsFromUrls(urlList); + + List templateSetConfigurations; + if (downloadedArtifacts.isEmpty()) { + templateSetConfigurations = ArtifactRetrieverUtil.retrieveArtifactsFromCache(null); + } else { + templateSetConfigurations = ArtifactRetrieverUtil.retrieveArtifactsFromCache(downloadedArtifacts); + } + ObservableList observableList = FXCollections.observableArrayList(); + + if (templateSetConfigurations != null) { + observableList.addAll(templateSetConfigurations); + this.searchResultsView.setItems(observableList); + } + + } + + /** + * Called when clearSearchResultsButton is clicked + */ + @FXML + public void clearSearchResults() { + + this.searchBar.clear(); + + // TODO: Should we show the Home Page when clearSearchResultsButton is clicked? + // try { + // this.controller.loadHome(null); + // } catch (IOException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + } + +} diff --git a/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/model/TemplateSetModel.java b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/model/TemplateSetModel.java new file mode 100644 index 0000000000..d4ae5b23bc --- /dev/null +++ b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/model/TemplateSetModel.java @@ -0,0 +1,52 @@ +package com.devonfw.cobigen.gui.model; + +import com.devonfw.cobigen.impl.config.entity.io.TemplateSetConfiguration; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +/** + * Singleton Model Class + * + */ +public class TemplateSetModel { + private static TemplateSetModel tsModel; + + private final ObservableList templateSetObservableList; + + private TemplateSetModel() { + + this.templateSetObservableList = FXCollections.observableArrayList(); + } + + public static TemplateSetModel getInstance() { + + if (tsModel == null) { + tsModel = new TemplateSetModel(); + } + + // returns the singleton object + return tsModel; + } + + /** + * @return templateSetObservableList + */ + public ObservableList getTemplateSetObservableList() { + + return this.templateSetObservableList; + } + + public void loadAllAvailableTemplateSets() { + + // Load all template set artifacts + // List templateSetConfigurations = ArtifactRetriever.retrieveArtifactsFromCache(); + + // pass TemplateSetConfigurations to GUI + // for (TemplateSetConfiguration configuration : templateSetConfigurations) { + // this.templateSetObservableList.addAll(configuration); + // } + + } + +} diff --git a/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/services/TemplateSetCell.java b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/services/TemplateSetCell.java new file mode 100644 index 0000000000..cafbdc0760 --- /dev/null +++ b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/services/TemplateSetCell.java @@ -0,0 +1,63 @@ +package com.devonfw.cobigen.gui.services; + +import java.io.IOException; + +import com.devonfw.cobigen.impl.config.entity.io.TemplateSetConfiguration; + +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ListCell; +import javafx.scene.layout.GridPane; + +/** + * TODO nneuhaus This type ... + * + */ +public class TemplateSetCell extends ListCell { + + FXMLLoader loader; + + @FXML + private GridPane gridPane; + + @FXML + private Label titleLabel; + + @FXML + private Button installButton; + + // when this method suppose to be called + @Override + protected void updateItem(TemplateSetConfiguration templateSet, boolean empty) { + + super.updateItem(templateSet, empty); + if (empty || templateSet == null) { + setText(""); + setGraphic(null); + setPrefHeight(45.0); + } else { + if (this.loader == null) { + this.loader = new FXMLLoader( + getClass().getClassLoader().getResource("com/devonfw/cobigen/gui/fxml/TemplateSetCell.fxml")); + this.loader.setController(this); + + try { + this.loader.load(); + } catch (IOException e) { + e.printStackTrace(); + } + } + // name of template set. should not happen here + this.titleLabel.setText(templateSet.getContextConfiguration().getTrigger().get(0).getId()); + this.installButton.setOnAction(event -> { + System.out.println("INSTALLIEREN!!!"); + }); + + setText(null); + setGraphic(this.gridPane); + } + } + +} diff --git a/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/services/TemplateSetCellFactory.java b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/services/TemplateSetCellFactory.java new file mode 100644 index 0000000000..af739982d0 --- /dev/null +++ b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/services/TemplateSetCellFactory.java @@ -0,0 +1,22 @@ +package com.devonfw.cobigen.gui.services; + +import com.devonfw.cobigen.impl.config.entity.io.TemplateSetConfiguration; + +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.util.Callback; + +/** + * TODO nneuhaus This type ... + * + */ +public class TemplateSetCellFactory + implements Callback, ListCell> { + + @Override + public ListCell call(ListView param) { + + return new TemplateSetCell(); + } + +} diff --git a/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/services/TreeViewBuilder.java b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/services/TreeViewBuilder.java new file mode 100644 index 0000000000..88620c12d2 --- /dev/null +++ b/cobigen/gui/src/main/java/com/devonfw/cobigen/gui/services/TreeViewBuilder.java @@ -0,0 +1,36 @@ +package com.devonfw.cobigen.gui.services; + +import java.util.List; + +import com.devonfw.cobigen.impl.config.entity.io.Increment; + +import javafx.scene.control.TreeItem; +import javafx.scene.control.TreeView; + +/** + * Service class to build Tree Views + * + */ +public class TreeViewBuilder { + + /** + * @param arrayOfItems to transform to tree + * @return the complete TreeView + */ + public static TreeView buildTreeView(List arrayOfItems) { + + TreeItem rootItem = new TreeItem<>("Increments"); + rootItem.setExpanded(true); + + for (Increment i : arrayOfItems) { + TreeItem increment = new TreeItem<>(i.getName()); + TreeItem incrementDescription = new TreeItem<>(i.getDescription()); + increment.getChildren().add(incrementDescription); + rootItem.getChildren().add(increment); + } + + TreeView tree = new TreeView<>(rootItem); + return tree; + } + +} diff --git a/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/dark_theme.css b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/dark_theme.css new file mode 100644 index 0000000000..ba790880b8 --- /dev/null +++ b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/dark_theme.css @@ -0,0 +1,105 @@ +.root { + -fx-accent: #1e74c6; + -fx-body-color : white; + -fx-outer-border : black; + -fx-focus-color: transparent; + -fx-faint-focus-color: transparent; + -fx-base: black; + -fx-accent: #0070AD; + -fx-control-inner-background: derive(-fx-base, 35.0%); + -fx-control-inner-background-alt: -fx-control-inner-background; +} + +.split-pane:horizontal > .split-pane-divider { + -fx-background-color: transparent; + -fx-padding: 0; +} +.split-pane:vertical > .split-pane-divider { + + -fx-padding: 0.5; +} + +/* Text */ +Text { + -fx-font: 12px Ubuntu; + -fx-fill: white; + -fx-font-weight: 200; + -fx-font-smoothing-type: lcd; +} +.header { + -fx-font-weight: 400; + -fx-font-size: 16.0px; +} +.subheader { + -fx-font-weight: 300; + -fx-font-size: 14.0px; +} + +/* Components */ +.label{ + -fx-text-fill: lightgray; +} + +.text-field { + -fx-background-color: -fx-text-box-border, -fx-background ; + -fx-background-insets: 0, 0 0 0 0 ; + -fx-background-radius: 0 ; + -fx-prompt-text-fill: gray; +} +.text-field:focused { + -fx-background-color: -fx-focus-color, -fx-background ; +} + +.button{ + -fx-focus-traversable: false; + -fx-background-color: -fx-control-inner-background, -fx-control-inner-background, -fx-control-inner-background; +} +#togglebutton{ + -fx-background-color: transparent; +} +#filterMenuButton{ + -fx-background-color: -fx-control-inner-background; +} + .titleBarButtons{ + -fx-background-color: transparent + } + +.icons{ + -fx-icon-color: -fx-body-color; +} +.button:default { + -fx-base: -fx-accent ; +} + +.button:hover{ + -fx-text-fill: white; +} + +.separator *.line { + -fx-background-color: #3C3C3C; + -fx-border-style: solid; + -fx-border-width: 1.0px; +} + +.scroll-bar { + -fx-background-color: derive(-fx-base,45.0%); + -fx-block-increment: 1.0; +} + +.list-cell:even, +.list-cell:odd { + -fx-control-inner-background: derive(-fx-base, 15.0%); +} + +.list-cell:empty { + -fx-background-color: transparent; +} + +.list-cell { + -fx-border-color: transparent; + -fx-table-cell-border-color:transparent; +} + +#menuBarPane{ + -fx-background-color: -fx-control-inner-background; +} \ No newline at end of file diff --git a/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/Details.fxml b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/Details.fxml new file mode 100644 index 0000000000..a77e379f95 --- /dev/null +++ b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/Details.fxml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/Home.fxml b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/Home.fxml new file mode 100644 index 0000000000..cfce1ece9f --- /dev/null +++ b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/Home.fxml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/Menu.fxml b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/Menu.fxml new file mode 100644 index 0000000000..40c94eb90a --- /dev/null +++ b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/Menu.fxml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/TemplateSetCell.fxml b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/TemplateSetCell.fxml new file mode 100644 index 0000000000..69e9396c6f --- /dev/null +++ b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/fxml/TemplateSetCell.fxml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/icons/devon-icon.jpg b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/icons/devon-icon.jpg new file mode 100644 index 0000000000..b6867b41e6 Binary files /dev/null and b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/icons/devon-icon.jpg differ diff --git a/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/styles.css b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/styles.css new file mode 100644 index 0000000000..b52ec4d159 --- /dev/null +++ b/cobigen/gui/src/main/resources/com/devonfw/cobigen/gui/styles.css @@ -0,0 +1,157 @@ +/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */ + +/* makes button and filter option white and borderless*/ +.root { + -fx-body-color : white; + -fx-outer-border : white; + +} +.root * { + -fx-font: 11.0px Ubuntu; + -fx-focus-color: transparent; + -fx-faint-focus-color: transparent; + -fx-base: white; + -fx-accent: #0070AD; + -fx-control-inner-background: derive(-fx-base, 35.0%); + -fx-control-inner-background-alt: -fx-control-inner-background; +} + +.split-pane:horizontal > .split-pane-divider { + -fx-background-color: transparent; + -fx-padding: 0.0; +} +.split-pane:vertical > .split-pane-divider { + -fx-padding: 0.5; +} + +.scroll-bar { + -fx-background-color: white; + -fx-block-increment: 1.0; +} + +/* Text */ +Text { + -fx-font: 12.0px Ubuntu; + -fx-fill: black; + -fx-font-weight: 200; + -fx-font-smoothing-type: lcd; +} +.header { + -fx-font-size: 16.0px; + -fx-font-weight: 400; +} +.subheader { + -fx-font-weight: 300; + -fx-font-size: 14.0px; +} + +.text-field { + -fx-background-color: -fx-text-box-border, -fx-background ; + -fx-background-insets: 0.0, 0.0 0.0 1.0 0.0 ; + -fx-background-radius: 0.0 ; + -fx-prompt-text-fill: gray; +} +.text-field:focused { + -fx-background-color: -fx-focus-color, -fx-background ; +} + +/* sets the color when cursor hovers over button*/ +color-picker:hover, +.date-picker:hover > .arrow-button, +.combo-box:hover,.choice-box:hover, +.number-button:hover,.left-arrow-button:hover,.right-arrow-button:hover, +.button:hover,.menu-button:hover,.toggle-button:hover, +.font-menu-button:hover, +.split-menu-button > .label:hover, .split-menu-button > .arrow-button:hover { + -fx-background-color: #ececec; + +} + + /*pressed selected*/ +.color-picker:pressed,.color-picker:selected, +.number-button:pressed,.number-button:selected, +.date-picker:pressed > .arrow-button, +.combo-box:pressed > .arrow-button,.combo-box:selected > .arrow-button, +.choice-box:pressed > .arrow-button,.choice-box:selected > .arrow-button, +.font-menu-button:pressed,.font-menu-button:selected, +.left-arrow-button:pressed,.left-arrow-button:selected, +.right-arrow-button:pressed,.right-arrow-button:selected, +.button:pressed, .button:selected,.menu-button:pressed,.menu-button:selected +,.toggle-button:pressed,.toggle-button:selected, +.split-menu-button:pressed > .label, .split-menu-button > .arrow-button:pressed { + -fx-background-color: #D3D3D3 + } + + #menuBarPane{ + -fx-background-color: white; + } + + #templateSetsLabel{ + -fx-background-color: transparent; + + } + + #homeButtonIcon{ + -fx-scale-x: 0.1; + -fx-scale-y: 0.1; + } + + .menuButtons{ + -fx-background-color: #0070AD + } + + .titleBarButtons{ + -fx-background-color: transparent + } + + #clearSearchButton{ + -fx-background-color: transparent + } + + /* Items in the search panel*/ +.list-cell:filled:selected:focused, .list-cell:filled:selected { + -fx-background-color: #0070AD; + -fx-text-fill: white; +} + +.list-cell:even { /* <=== changed to even */ + -fx-background-color: white; +} + +.list-cell:filled:hover { + -fx-background-color: #12B3DB; + -fx-text-fill: white; +} + +list-view { + -fx-background-color: white; +} + +.list-cell:odd { +-fx-background-color: white; + +} + +.split-menu-button { + -fx-background-color: #0070AD, #0070AD; + +} +.split-menu-button > .label { + -fx-text-fill: white; + -fx-background-color: #0070AD, #0070AD; +} +.split-menu-button > .arrow-button { + -fx-background-color: #0070AD, #0070AD; + +} +.split-menu-button:hover { + -fx-background-color: #0070AD; +} +.split-menu-button:hover > .label { + -fx-background-color: #0070AD, #0070AD, transparent, #0070AD; + +} +.split-menu-button:hover > .arrow-button { + -fx-background-color: #ececec, #ececec, #ececec, #ececec; + +} diff --git a/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/FilterTest.java b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/FilterTest.java new file mode 100644 index 0000000000..a8c044d07e --- /dev/null +++ b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/FilterTest.java @@ -0,0 +1,73 @@ +package com.devonfw.cobigen.gui; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * TODO nneuhaus This type ... + * + */ +public class FilterTest extends TestFXBase { + + /** + * + */ + @Test + public void testAdaptedView() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testInstalledView() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testCheckForUpdates() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void showsAllTags() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void selectAndDeselectTag() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void selectMultipleTags() { + + // TODO + assertThat(false).isTrue(); + } + +} diff --git a/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/HomePageTest.java b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/HomePageTest.java new file mode 100644 index 0000000000..bd1f533d87 --- /dev/null +++ b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/HomePageTest.java @@ -0,0 +1,91 @@ +package com.devonfw.cobigen.gui; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; +import org.testfx.api.FxRobotException; + +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.Hyperlink; +import javafx.scene.control.TreeItem; +import javafx.scene.control.TreeView; + +/** + * Tests for the home page + * + */ +public class HomePageTest extends TestFXBase { + + @FXML + private Hyperlink wikilink; + + @FXML + private TreeView incrementsTreeView; + + /** + * Test if exception is thrown, when the bot tries to click a not existing element + */ + @Test(expected = FxRobotException.class) + public void clickOnBogusElement() { + + clickOn("#NotExisting"); + } + + /** + * Test if home page is shown when GUI is started + */ + @Test + public void ensureHomePageIsShownOnStartUp() { + + assertThat(this.home); + } + + /** + * Test if home page is shown when Home Button gets clicked + */ + // @Test + // public void ensureHomePageIsShownOnHomeButtonClicked() { + // + // this.searchResultsView.getSelectionModel().select(0); + // assertThat(this.searchResultsView.getSelectionModel().getSelectedIndex() == 0); + // assertThat(this.details.isVisible()); + // assertThat(!this.home.isVisible()); + // // Switch back to Home + // clickOn("#homeButton"); + // assertThat(this.home.isVisible()); + // assertThat(!this.details.isVisible()); + // } + + /** + * Test if link to Cobigen Wiki works + */ + @Test + public void testLinkToCobigenWiki() { + + String COBIGEN_WIKI_LINK = "#wikilink"; + this.wikilink = find(COBIGEN_WIKI_LINK); + assertThat(!this.wikilink.isPressed()); + clickOn(COBIGEN_WIKI_LINK); + assertThat(this.wikilink.isPressed()); + } + + /** + * Test if the example tree view is interactive + */ + @Test + public void testFoldingIncrementTreeView() { + + String TREEVIEW = "#treeView"; + this.incrementsTreeView = (TreeView) this.mainRoot.lookup(TREEVIEW); + TreeItem root = this.incrementsTreeView.getRoot(); + assertThat(root.isExpanded()); + ObservableList> children = root.getChildren(); + for (int i = 0; i < children.size(); i++) { + TreeItem child = children.get(i); + assertThat(!child.isExpanded()); + assertThat(child.getChildren().get(0).isLeaf()); + } + } + +} diff --git a/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/ProcessTemplateSetTest.java b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/ProcessTemplateSetTest.java new file mode 100644 index 0000000000..20b91375cc --- /dev/null +++ b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/ProcessTemplateSetTest.java @@ -0,0 +1,207 @@ +package com.devonfw.cobigen.gui; + +import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +import org.apache.commons.io.FileUtils; +import org.junit.Test; +import org.testfx.util.WaitForAsyncUtils; + +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.api.util.CobiGenPaths; + +import javafx.scene.control.Button; + +/** + * TODO + * + */ +public class ProcessTemplateSetTest extends TestFXBase { + + /** + * Root path to all resources used in this test case + */ + private final static Path TEST_FILE_ROOT_PATH = Paths + .get("src/test/resources/testdata/integrationtests/ProcessTemplateSetTest"); + + @Test + public void testGetAllTemplateSetsAdapted() throws Exception { + + // TODO: + this.tmpFolder.newFolder(ConfigurationConstants.TEMPLATE_SETS_FOLDER); + this.tmpFolder.newFolder(ConfigurationConstants.TEMPLATE_SETS_FOLDER, ConfigurationConstants.ADAPTED_FOLDER); + + } + + /** + * Tests if a selected template set can be installed (template-set class jar file gets added to + * template-sets/downloaded folder) and the text of the install button changed from Install to Installed + * + * @throws Exception Test fails + */ + @Test + public void testInstallTemplateSet() throws Exception { + + // preparation + File downloaded = this.tmpFolder.newFolder("UserHome", ConfigurationConstants.TEMPLATE_SETS_FOLDER, + ConfigurationConstants.DOWNLOADED_FOLDER); + + // simulate template-set-list folder for downloaded template-set.xml files to be used in GUI + File artifactCacheFolder = this.tmpFolder.newFolder("UserHome", "template-sets", "template-set-list"); + + Path templateSetXmlFile1 = TEST_FILE_ROOT_PATH.resolve("crud-java-server-app-2021.12.007-template-set.xml"); + Files.copy(templateSetXmlFile1, + artifactCacheFolder.toPath().resolve("crud-java-server-app-2021.12.007-template-set.xml"), + StandardCopyOption.REPLACE_EXISTING); + Path templateSetXmlFile2 = TEST_FILE_ROOT_PATH.resolve("crud-openapi-server-app-2021.12.007-template-set.xml"); + Files.copy(templateSetXmlFile2, + artifactCacheFolder.toPath().resolve("crud-openapi-server-app-2021.12.007-template-set.xml"), + StandardCopyOption.REPLACE_EXISTING); + + Button refreshButton = find("#refreshButton"); + clickOn(refreshButton); + + WaitForAsyncUtils.waitForFxEvents(); + + // clicks on first element of searchResultsView + clickOn(this.searchResultsView.getItems().get(0).getContextConfiguration().getTrigger().get(0).getId()); + + Button installButton = find("#installButton"); + String installButtonText = installButton.getText(); + + sleep(1000); + + clickOn("Install"); + + WaitForAsyncUtils.waitForFxEvents(); + + assertThat(downloaded.toPath().resolve("crud-java-server-app-2021.12.007.jar")).exists(); + + assertThat(installButtonText).isEqualTo("Installed"); + + } + + @Test + public void testGetAllTemplateSetsDownloaded() throws Exception { + + // preparation + File userHome = this.tmpFolder.newFolder("UserHome"); + + Path templateSetPath = TEST_FILE_ROOT_PATH.resolve("downloaded_template_sets/template-sets"); + + FileUtils.copyDirectory(templateSetPath.toFile(), userHome.toPath().resolve("template-sets").toFile()); + + withEnvironmentVariable(ConfigurationConstants.CONFIG_ENV_HOME, userHome.getAbsolutePath()).execute(() -> { + Path downloadedPath = CobiGenPaths.getTemplateSetsFolderPath().resolve(ConfigurationConstants.DOWNLOADED_FOLDER); + + }); + + } + + @Test + public void testGetAllTemplateSetsInstalled() throws Exception { + + File userHome = this.tmpFolder.newFolder("user-home"); + + // List templateSets = ArtifactRetriever.retrieveTemplateSetData(); + + } + + @Test + public void testGetAllTemplateSetsInfo() { + + } + + // TODO: WireMock + // ConfigurationUtilTest + @Test + public void testGetAllTemplateSetsFromRepo() { + + } + + /** + * + */ + @Test + public void testAllTemplateSetsAreShownWithTrueStatus() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testInstallTemplateSetThroughDetails() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testUpdateTemplateSetThroughDetails() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testUpdateTemplateSetToCertainVersion() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testUninstallTemplateSetThroughDetails() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testInstallTemplateSetThroughSearchResultCell() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testUpdateTemplateSetThroughSearchResultCell() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testUninstallTemplateSetThroughSearchResultCell() { + + // TODO + assertThat(false).isTrue(); + } +} diff --git a/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/SearchTest.java b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/SearchTest.java new file mode 100644 index 0000000000..31e9d2d0af --- /dev/null +++ b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/SearchTest.java @@ -0,0 +1,147 @@ +package com.devonfw.cobigen.gui; + +import org.junit.Test; + +import javafx.scene.control.Label; +import javafx.scene.control.TextField; + +/** + * Tests for the search function + * + */ +public class SearchTest extends TestFXBase { + + /** + * Tests if search results list view has the correct list cells + */ + @Test + public void hasListCell() { + + // assertThat(this.searchResultsView).hasListCell(this.templateSetObservableList.get(0)); + } + + /** + * Tests that error is thrown when asked for null list cell + */ + @Test + public void hasListCellFailsWithNull() { + + // assertThatThrownBy(() -> assertThat(this.searchResultsView).hasListCell(null)) + // .isExactlyInstanceOf(AssertionError.class); + } + + /** + * Tests that error is thrown when asked for bogus list cell + */ + @Test + public void hasListCellFailsWithBogus() { + + // assertThatThrownBy(() -> assertThat(this.searchResultsView).hasListCell(this.BOGUS)) + // .isExactlyInstanceOf(AssertionError.class); + } + + /** + * Tests that the search results have no bogus list cell + */ + @Test + public void doesNotHaveListCell() { + + // assertThat(this.searchResultsView).doesNotHaveListCell(this.BOGUS); + } + + /** + * Tests that the amount of elements in the list are shown in the search results + */ + @Test + public void hasExactlyNumItems() { + + // assertThat(this.searchResultsView).hasExactlyNumItems(this.templateSetObservableList.size()); + } + + /** + * Tests that error is thrown when asked for wrong count of items + */ + @Test + public void hasExactlyNumItems_fails() { + + // assertThatThrownBy(() -> assertThat(this.searchResultsView).hasExactlyNumItems(1)) + // .isExactlyInstanceOf(AssertionError.class).hasMessage( + // "Expected: ListView has exactly 1 item\n " + "but: was " + this.templateSetObservableList.size()); + } + + /** + * Tests that correct items are shown in the search results before the search + */ + @Test + public void preSearchTest() { + + // int i = 0; + // for (TemplateSet ts : this.templateSetObservableList) { + // clickOn("#searchResultsView"); + // assertThat(this.searchResultsView.getSelectionModel().getSelectedIndex() == i); + // assertThat(ts.equals(this.searchResultsView.getItems().get(i))).isTrue(); + // i++; + // } + } + + /** + * Tests that each template set is the only search result when searched for its exact name + */ + @Test + public void ensureAllTemplateSetsAreFound() { + + String titleOfTemplateSet; + TextField searchBar = find("#searchBar"); + // for (TemplateSet ts : this.templateSetObservableList) { + // clickOn("#searchBar"); + // titleOfTemplateSet = ts.getName(); + // eraseText(titleOfTemplateSet.length()); + // write(titleOfTemplateSet); + // clickOn("#searchResultsView"); + // assertThat(titleOfTemplateSet.equals(this.searchResultsView.getItems().get(0).getName())); + // assertThat(this.searchResultsView).hasExactlyNumItems(1); + } + + /** + * Tests that there are no search results shown with a bogus search term + */ + @Test + public void ensureSearchResultsEmptyWithBogusSearchTerm() { + + clickOn("#searchBar"); + write(this.BOGUS); + // assertThat(this.searchResultsView).hasExactlyNumItems(0); + } + + /** + * Tests functionality of the clearSearchResultsButton + */ + @Test + public void testClearSearchResultsButton() { + + // + // int originalItemCount = this.searchResultsView.getItems().size(); + // TextField searchBar = find("#searchBar"); + // clickOn("#searchBar"); + // write(this.templateSetObservableList.get(0).getName()); + // assertThat(this.searchResultsView).hasExactlyNumItems(1); + // clickOn("#clearSearchResultsButton"); + // assertThat(searchBar.getText().length() == 0); + // assertThat(this.searchResultsView).hasExactlyNumItems(originalItemCount); + } + + /** + * Selects all items in the search results and tests if the correct template set details page is shown + */ + @Test + public void testSelectionOfTemplateSet() { + + Label titleLabel; + // for (int i = 0; i < this.templateSetObservableList.size(); i++) { + // this.searchResultsView.getSelectionModel().select(i); + // titleLabel = find("#titleLabel"); + // assertThat(titleLabel.getText() == this.searchResultsView.getSelectionModel().getSelectedItem().getName()); + // } + } + +} diff --git a/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/TemplateSetDetailsTest.java b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/TemplateSetDetailsTest.java new file mode 100644 index 0000000000..79f93d10dc --- /dev/null +++ b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/TemplateSetDetailsTest.java @@ -0,0 +1,135 @@ +package com.devonfw.cobigen.gui; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.Test; + +import com.devonfw.cobigen.impl.config.entity.io.TemplateSetConfiguration; +import com.devonfw.cobigen.impl.config.reader.TemplateSetConfigurationReader; + +import javafx.collections.FXCollections; + +/** + * TODO + * + */ +public class TemplateSetDetailsTest extends TestFXBase { + + /** + * Root path to all resources used in this test case + */ + private final static Path TEST_FILE_ROOT_PATH = Paths + .get("src/test/resources/testdata/unittests/TemplateSetDetailsTest"); + + /** + * + */ + @Test + public void testVisibilityOnStartUp() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testVisibilityAfterSearchAndSelect() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * Tests if a loaded template set is displaying the correct name in the list view + */ + @Test + public void testTemplateSetNameIsShownCorrectly() { + + Path templateSetXmlFile = TEST_FILE_ROOT_PATH.resolve("template-set.xml"); + + // initialize template set reader + TemplateSetConfigurationReader reader = new TemplateSetConfigurationReader(templateSetXmlFile); + + // read template set xml file/files + reader.readConfiguration(templateSetXmlFile); + + TemplateSetConfiguration templateSetConfiguration = reader.getTemplateSetConfiguration(); + + // adds template set to GUI + this.templateSetObservableList = FXCollections.observableArrayList(); + this.templateSetObservableList.addAll(templateSetConfiguration); + + this.searchResultsView.setItems(this.templateSetObservableList); + + String triggerName = templateSetConfiguration.getContextConfiguration().getTrigger().get(0).getId(); + String templateSetNameInMenu = this.searchResultsView.getItems().get(0).getContextConfiguration().getTrigger() + .get(0).getId(); + + assertThat(templateSetNameInMenu).isEqualTo(triggerName); + } + + /** + * + */ + @Test + public void testTemplateSetDescriptionIsShownCorrectly() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testTemplateSetStatusIsShownCorrectly() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testTemplateSetVersionIsShownCorrectly() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testSelectableVersionsAreShownCorrectly() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testInstallButtonDisabledForInstalledTemplateSet() { + + // TODO + assertThat(false).isTrue(); + } + + /** + * + */ + @Test + public void testTemplateSetStructureIsShownCorrectly() { + + // TODO + assertThat(false).isTrue(); + } +} diff --git a/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/TestFXBase.java b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/TestFXBase.java new file mode 100644 index 0000000000..a832de631e --- /dev/null +++ b/cobigen/gui/src/test/java/com/devonfw/cobigen/gui/TestFXBase.java @@ -0,0 +1,137 @@ +package com.devonfw.cobigen.gui; + +import java.io.File; +import java.io.IOException; +import java.util.ResourceBundle; +import java.util.concurrent.TimeoutException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TemporaryFolder; +import org.testfx.api.FxToolkit; +import org.testfx.framework.junit.ApplicationTest; + +import com.devonfw.cobigen.api.util.CobiGenPaths; +import com.devonfw.cobigen.gui.controllers.DetailsController; +import com.devonfw.cobigen.gui.controllers.MenuController; +import com.devonfw.cobigen.impl.config.entity.io.TemplateSetConfiguration; + +import javafx.collections.ObservableList; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.ListView; +import javafx.scene.input.KeyCode; +import javafx.scene.input.MouseButton; +import javafx.scene.layout.Pane; +import javafx.stage.Stage; + +/** + * Base Test + * + */ +public class TestFXBase extends ApplicationTest { + + final String BOGUS = "NOT EXISTING TEMPLATE SET"; + + Pane mainRoot; + + Stage mainStage; + + Controller controller; + + Parent home; + + Parent details; + + MenuController menuController; + + DetailsController detailsController; + + ListView searchResultsView; + + ObservableList templateSetObservableList; + + protected static ResourceBundle bundle; + + /** Temporary files rule to create temporary folders or files */ + @Rule + public TemporaryFolder tmpFolder = new TemporaryFolder(); + + public static File userHome = null; + + /** + * Set up headless testing + * + * @throws IOException + */ + @Before + public void setupHeadlessMode() throws IOException { + + userHome = this.tmpFolder.newFolder("UserHome"); + this.tmpFolder.newFolder("UserHome", "template-sets"); + CobiGenPaths.setCobiGenHomeTestPath(userHome.toPath().toAbsolutePath()); + + if (Boolean.getBoolean("headless")) { + System.setProperty("testfx.robot", "glass"); + System.setProperty("testfx.headless", "true"); + System.setProperty("prism.order", "sw"); + System.setProperty("prism.text", "t2k"); + System.setProperty("java.awt.headless", "true"); + } + + // bundle = ResourceBundle.getBundle("Bundle"); + } + + /** + * Start the GUI and set everything up + */ + @Override + public void start(Stage stage) throws Exception { + + this.mainStage = stage; + FXMLLoader loader = new FXMLLoader(getClass().getResource("fxml/Primary.fxml")); + this.mainRoot = loader.load(); + this.controller = loader.getController(); + stage.setScene(new Scene(this.mainRoot)); + stage.show(); + stage.toFront(); + + this.home = find("#home"); + this.details = find("#details"); + this.menuController = this.controller.menuController; + this.detailsController = this.controller.detailsController; + this.searchResultsView = find("#searchResultsView"); + // this.templateSetObservableList = this.menuController.templateSetObservableList; + } + + /** + * @throws TimeoutException + */ + @After + public void afterEachTest() throws TimeoutException { + + FxToolkit.hideStage(); + release(new KeyCode[] {}); + release(new MouseButton[] {}); + } + + /** + * Helper method to retrieve Java FX GUI components + * + * @param + * @param query + * @return + */ + @SuppressWarnings("unchecked") + public T find(final String query) { + + // temporary 'fix' because lookup(#home)... throws error + return (T) this.mainStage.getScene().lookup(query); + + // return (T) lookup(query).queryAll().iterator().next(); + } + +} diff --git a/cobigen/gui/src/test/resources/template-set.xml b/cobigen/gui/src/test/resources/template-set.xml new file mode 100644 index 0000000000..3b7e837efa --- /dev/null +++ b/cobigen/gui/src/test/resources/template-set.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cobigen/gui/src/test/resources/testdata/integrationtests/ProcessTemplateSetTest/crud-java-server-app-2021.12.007-template-set.xml b/cobigen/gui/src/test/resources/testdata/integrationtests/ProcessTemplateSetTest/crud-java-server-app-2021.12.007-template-set.xml new file mode 100644 index 0000000000..7790a68bbf --- /dev/null +++ b/cobigen/gui/src/test/resources/testdata/integrationtests/ProcessTemplateSetTest/crud-java-server-app-2021.12.007-template-set.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cobigen/gui/src/test/resources/testdata/integrationtests/ProcessTemplateSetTest/crud-openapi-server-app-2021.12.007-template-set.xml b/cobigen/gui/src/test/resources/testdata/integrationtests/ProcessTemplateSetTest/crud-openapi-server-app-2021.12.007-template-set.xml new file mode 100644 index 0000000000..6a7e091ee8 --- /dev/null +++ b/cobigen/gui/src/test/resources/testdata/integrationtests/ProcessTemplateSetTest/crud-openapi-server-app-2021.12.007-template-set.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cobigen/gui/src/test/resources/testdata/unittests/TemplateSetDetailsTest/template-set.xml b/cobigen/gui/src/test/resources/testdata/unittests/TemplateSetDetailsTest/template-set.xml new file mode 100644 index 0000000000..c80976b27b --- /dev/null +++ b/cobigen/gui/src/test/resources/testdata/unittests/TemplateSetDetailsTest/template-set.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cobigen/pom.xml b/cobigen/pom.xml index 2c2b6d5a7f..f13661d83e 100644 --- a/cobigen/pom.xml +++ b/cobigen/pom.xml @@ -18,5 +18,6 @@ cobigen-core-systemtest core-externalprocess-api core-artifact-retriever + gui \ No newline at end of file diff --git a/pom.xml b/pom.xml index e0f14f7dbf..42392412d9 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,5 @@ - + 4.0.0 com.devonfw.cobigen master-parent @@ -213,6 +213,11 @@ core-test ${revision} + + com.devonfw.cobigen + gui + ${revision} + com.devonfw.cobigen javaplugin