diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..9c38753c --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,76 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + #branches: [ "master" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master" ] + schedule: + - cron: '16 2 * * 2' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'java' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Use only 'java' to analyze code written in Java, Kotlin or both + # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml new file mode 100644 index 00000000..d5dc22af --- /dev/null +++ b/.github/workflows/sonarcloud.yml @@ -0,0 +1,68 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow helps you trigger a SonarCloud analysis of your code and populates +# GitHub Code Scanning alerts with the vulnerabilities found. +# Free for open source project. + +# 1. Login to SonarCloud.io using your GitHub account + +# 2. Import your project on SonarCloud +# * Add your GitHub organization first, then add your repository as a new project. +# * Please note that many languages are eligible for automatic analysis, +# which means that the analysis will start automatically without the need to set up GitHub Actions. +# * This behavior can be changed in Administration > Analysis Method. +# +# 3. Follow the SonarCloud in-product tutorial +# * a. Copy/paste the Project Key and the Organization Key into the args parameter below +# (You'll find this information in SonarCloud. Click on "Information" at the bottom left) +# +# * b. Generate a new token and add it to your Github repository's secrets using the name SONAR_TOKEN +# (On SonarCloud, click on your avatar on top-right > My account > Security +# or go directly to https://sonarcloud.io/account/security/) + +# Feel free to take a look at our documentation (https://docs.sonarcloud.io/getting-started/github/) +# or reach out to our community forum if you need some help (https://community.sonarsource.com/c/help/sc/9) + +name: SonarCloud analysis + +on: + push: + #branches: [ "master" ] + pull_request: + branches: [ "master" ] + workflow_dispatch: + +permissions: + pull-requests: read # allows SonarCloud to decorate PRs with analysis results + +jobs: + Analysis: + runs-on: ubuntu-latest + + steps: + - name: Analyze with SonarCloud + + # You can pin the exact commit or the version. + # uses: SonarSource/sonarcloud-github-action@de2e56b42aa84d0b1c5b622644ac17e505c9a049 + uses: SonarSource/sonarcloud-github-action@de2e56b42aa84d0b1c5b622644ac17e505c9a049 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Generate a token on Sonarcloud.io, add it to the secrets of this repo with the name SONAR_TOKEN (Settings > Secrets > Actions > add new repository secret) + with: + # Additional arguments for the sonarcloud scanner + args: + # Unique keys of your project and organization. You can find them in SonarCloud > Information (bottom-left menu) + # mandatory + -Dsonar.projectKey=${{ secrets.PROJECT_KEY }} + -Dsonar.organization=${{ secrets.ORGANIZATION_NAME }} + # Comma-separated paths to directories containing main source files. + #-Dsonar.sources= # optional, default is project base directory + # When you need the analysis to take place in a directory other than the one from which it was launched + #-Dsonar.projectBaseDir= # optional, default is . + # Comma-separated paths to directories containing test source files. + #-Dsonar.tests= # optional. For more info about Code Coverage, please refer to https://docs.sonarcloud.io/enriching/test-coverage/overview/ + # Adds more detail to both client and server-side analysis logs, activating DEBUG mode for the scanner, and adding client-side environment variables and system properties to the server-side log of analysis report processing. + #-Dsonar.verbose= # optional, default is false diff --git a/src/main/java/de/doubleslash/keeptime/common/RandomColorPicker.java b/src/main/java/de/doubleslash/keeptime/common/RandomColorPicker.java new file mode 100644 index 00000000..a80fbcda --- /dev/null +++ b/src/main/java/de/doubleslash/keeptime/common/RandomColorPicker.java @@ -0,0 +1,82 @@ +package de.doubleslash.keeptime.common; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javafx.scene.paint.Color; + +public class RandomColorPicker { + private static final Logger LOG = LoggerFactory.getLogger(RandomColorPicker.class); + + public static List colors = new ArrayList<>(); + + static { + try { + fillColorList(); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static Color getRandomColor(List colorList) { + + int rnd = new Random().nextInt(colorList.size()); + return colorList.get(rnd); + } + + private static void fillColorList() throws IllegalAccessException { + Field[] field = Color.class.getFields(); + if (field != null) { + for (int i = 0; i < field.length; i++) { + Field f = field[i]; + Object obj = f.get(null); + if (obj instanceof Color) { + colors.add((Color) obj); + } + } + } + } + + public static Color chooseContrastColor(List availableColors, Color backgroundColor,Color hoverbackgroundColor) { + + double divAdd = 0; + Color divColor = null; + int maxTries = 0; + + while (divAdd < 1 && maxTries < 10) { + divColor = getUniqueColor(availableColors, backgroundColor, hoverbackgroundColor); + double divred = Math.abs(divColor.getRed() - backgroundColor.getRed()); + double divgreen = Math.abs(divColor.getGreen() - backgroundColor.getGreen()); + double divblue = Math.abs(divColor.getBlue() - backgroundColor.getBlue()); + divAdd = divblue + divgreen + divred; + maxTries++; + } + return divColor; + } + + public static Color getUniqueColor(List availableColors, Color backgroundColor, Color hoverbackgroundColor) { + + List uniqueColorList = new ArrayList<>(colors); + uniqueColorList.remove(backgroundColor); // List should remove all already used colors. + uniqueColorList.remove(hoverbackgroundColor); + for (Color color : availableColors) { + for (int i = 0; i < uniqueColorList.size(); i++) { + + if (color.toString().equals(uniqueColorList.get(i).toString())) { + uniqueColorList.remove(i); + } + } + } + if(uniqueColorList.isEmpty()){ + LOG.info("Empty uniqueColorList return Black"); + return Color.BLACK; + } + return getRandomColor(uniqueColorList); + } + +} diff --git a/src/main/java/de/doubleslash/keeptime/common/Resources.java b/src/main/java/de/doubleslash/keeptime/common/Resources.java index 12310945..e985655f 100644 --- a/src/main/java/de/doubleslash/keeptime/common/Resources.java +++ b/src/main/java/de/doubleslash/keeptime/common/Resources.java @@ -67,7 +67,9 @@ public enum RESOURCE { SVG_LICENSES_ICON("/svgs/closed-captioning.svg"), - ICON_MAIN("/icons/icon.png") + SVG_RANDOM_COLOR_BUTTON("/svgs/dice.svg"), + + ICON_MAIN("/icons/icon.png"), ; diff --git a/src/main/java/de/doubleslash/keeptime/view/ManageProjectController.java b/src/main/java/de/doubleslash/keeptime/view/ManageProjectController.java index 5ff849a6..84e84bf9 100644 --- a/src/main/java/de/doubleslash/keeptime/view/ManageProjectController.java +++ b/src/main/java/de/doubleslash/keeptime/view/ManageProjectController.java @@ -16,6 +16,11 @@ package de.doubleslash.keeptime.view; +import static de.doubleslash.keeptime.view.ViewController.fontColorProperty; + +import java.util.ArrayList; +import java.util.List; + import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -25,11 +30,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import de.doubleslash.keeptime.common.RandomColorPicker; +import de.doubleslash.keeptime.common.Resources; +import de.doubleslash.keeptime.common.SvgNodeProvider; import de.doubleslash.keeptime.model.Model; import de.doubleslash.keeptime.model.Project; import javafx.fxml.FXML; +import javafx.scene.control.*; import javafx.scene.control.SpinnerValueFactory.IntegerSpinnerValueFactory; import javafx.scene.layout.GridPane; +import javafx.scene.paint.Color; +import javafx.scene.shape.SVGPath; @Component public class ManageProjectController { @@ -56,6 +67,9 @@ public class ManageProjectController { @FXML private Spinner sortIndexSpinner; + @FXML + private Button randomColorButton; + @FXML private Label validateTextAlert; @@ -73,6 +87,25 @@ private void initialize() { sortIndexSpinner.getValueFactory().setValue(model.getAvailableProjects().size()); formValidProperty.bind(Bindings.createBooleanBinding(() -> !nameTextField.getText().isBlank(),nameTextField.textProperty())); validateTextAlert.visibleProperty().bind(formValidProperty.not()); + randomColorButton.setOnAction(event -> setRandomColor()); + + SVGPath calendarSvgPath = SvgNodeProvider.getSvgNodeWithScale(Resources.RESOURCE.SVG_RANDOM_COLOR_BUTTON, 0.04, + 0.04); + calendarSvgPath.fillProperty().bind(fontColorProperty); + randomColorButton.setGraphic(calendarSvgPath); + } + + private void setRandomColor() { + textFillColorPicker.setValue( + RandomColorPicker.chooseContrastColor( getProjectColorList(), model.defaultBackgroundColor.get(), model.hoverBackgroundColor.get())); + } + + private List getProjectColorList() { + List colorList = new ArrayList<>(); + for (Project project : model.getAllProjects()) { + colorList.add(project.getColor()); + } + return colorList; } public void initializeWith(final Project project) { diff --git a/src/main/resources/layouts/manage-project.fxml b/src/main/resources/layouts/manage-project.fxml index b979f990..39bf3ca8 100644 --- a/src/main/resources/layouts/manage-project.fxml +++ b/src/main/resources/layouts/manage-project.fxml @@ -1,6 +1,7 @@ + @@ -9,6 +10,7 @@ + @@ -33,7 +35,6 @@