Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ingmar.forsberg/lab4
  • Leon.Dammann/lab-4-inf-101
  • markus.trohjell/lab4
  • Viktor.Yordanov/lab4
  • Anders.Sortun/lab-4-v-23
  • amilia.storm/lab4
  • Ola.Kristoffersen/lab-4-2
  • Malvika.Singh/lab4
  • ii/inf101/23v/students/lab4
  • Henrik.Dalsto/lab4
  • Olav.Eikanger/lab4
  • shahnaz.mhethawy/lab4
  • ole-andreas.jensen/lab4
  • Qingle.Xu/lab4
  • Axel.Lundeby/lab4
  • Emma.Wergedahl/lab4
  • Kai.Waloen/lab4
  • R.Bortne/lab4
  • Thomas.T.Jensen/lab4
  • Halfdan.Hesthammer/lab-4-inf-101-v-23
  • Natanem.Hailu/lab4
  • Julie.Mikkelsen/lab-4-jm
  • Stine.Fanebust/lab4
  • Martin.Aasenhuus/lab4
  • Oscar.Stromsli/inf-101-lab-4
  • Jan.Brunner/lab-4-2023
  • Mathias.Handeland/lab4
  • Theodor.Nissen-Meyer/lab4
  • V.Larsen/lab4
  • Havard.Kolve/lab4
  • Dag.Himle/lab4
  • Benjamin.Fossbakken/lab4
  • Martin.Fausa/lab4
  • Fernando.Aguilar/lab4
  • Mattias.Nordahl/lab-4-v-23
  • Olav.Skogen/lab4
  • Marius.Jorgensen/lab4
  • David.Mo/lab4
  • Henrik.Tennebekk/lab4
  • Cecilie.Tveter/lab-4-inf-101-v-23
  • Lauritz.Angeltveit/lab4
  • Kristian.Roynestad/lab4
  • Julie.Hallan/lab4
  • Stian.Bekkeheien/lab-4-inf-101
  • Mattias.Nordahl/lab-4-v-23-1
  • Jacob.Grahm-Haga/lab4
  • Elias.Aronsen/lab-4-23-v
  • Henrik.Skjeret/lab-4-v-23
48 results
Show changes
Commits on Source (12)
Showing
with 867 additions and 262 deletions
mvnw
mvnw.cmd
# Created by https://www.toptal.com/developers/gitignore/api/eclipse,maven,java,intellij,visualstudiocode,macos,windows
# Edit at https://www.toptal.com/developers/gitignore?templates=eclipse,maven,java,intellij,visualstudiocode,macos,windows
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
### Eclipse Patch ###
# Spring Boot Tooling
.sts4-cache/
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/
# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml
# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/
# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$
# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml
# Azure Toolkit for IntelliJ plugin
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
.idea/**/azureSettings.xml
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
# Eclipse m2e generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/eclipse,maven,java,intellij,visualstudiocode,macos,windows
target/
.mvn/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
\ No newline at end of file
......@@ -2,7 +2,7 @@
![Illustrasjon av ferdig program](./img/screenshot-done.png)
I denne lab'en skal vi tegne et rutenett som vist over. Oppgaven består i hovedsak av to deler:
I denne lab'en skal vi tegne et rutenett som vist over. Oppgaven består i hovedsak av tre deler:
1. Skriv en klasse `ColorGrid` som representerer et rutenett av farger.
2. Skriv en klasse `CellPositionToPixelConverter` som har en metode som regner ut piksel-koordinatene for en gitt rute.
2. Skriv en klasse `GridView` som kan tegne et rutenett av farger.
......@@ -14,13 +14,15 @@ I denne lab'en skal vi tegne et rutenett som vist over. Oppgaven består i hoved
* [Opprett rutetnettet som skal tegnes](#opprett-rutenettet-som-skal-tegnes)
* [CellPositionToPixelConverter](#cellpositiontopixelconverter)
* [drawGrid](#drawgrid)
* [drawCell](#drawcell)
* [drawCells](#drawcells)
* [Bonusoppgave](#bonusoppgave)
## Anbefalte forberedelser
* Laben antar at du har kjennskap til grunnleggende java, inkludert [grensesnitt](https://inf101.ii.uib.no/notat/grensesnitt/), [klasser og objekter](https://inf101.ii.uib.no/notat/objekter/).
* Du bør ha skummet igjennom kursnotatene om [arv](https://inf101.ii.uib.no/notat/arv), men vi kommer ikke til å gå i dypden på dette i denne lab'en.
* Kursnotatene om [grafikk](https://inf101.ii.uib.no/notat/grafikk) vil være spesielt relevante. Kan brukes som et oppslagsverk for å finne ut hvordan noe kan tegnes.
* I den utleverte koden dukker det opp to *record*-klasser. Du trenger ikke sette deg inn i mutabilitet for denne lab'en, men kursnotatene om dette inneholder også et [avsnitt om record-klasser](https://inf101.ii.uib.no/notat/mutabilitet/#record) hvor det er verdt å skumme gjennom eksempelet som demonstrerer bruken.
* Kursnotatene om [grafikk](https://inf101.ii.uib.no/notat/grafikk) vil naturligvis være spesielt relevante, primært de tre første avsnittene om rammeverket, koordinatsystemet og grunnleggende figurer; men også hjelpemetoder, farger og adaptiv tegning blir adressert i lab'en.
## Bli kjent med utlevert kode
......@@ -39,11 +41,15 @@ I denne oppgaven skal du lage klassen `ColorGrid` ([link](./src/main/java/no/uib
Du kan leke deg litt i `Main::main` for å sjekke for deg selv at klassen fungerer som du forventer. For eksempel:
```java
// Opprett et rutenett med 3 rader og 4 kolonner
IColorGrid grid = new ColorGrid(3, 4);
System.out.println(grid.rows()); // forventer 3
System.out.println(grid.cols()); // forventer 4
// Sjekk at standard-verdien er null
System.out.println(grid.get(new CellPosition(1, 2))); // forventer null
// Sjekk at vi kan endre verdien på en gitt posisjon
grid.set(new CellPosition(1, 2), Color.RED);
System.out.println(grid.get(new CellPosition(1, 2))); // forventer rød
System.out.println(grid.get(new CellPosition(2, 1))); // forventer null
......@@ -83,14 +89,16 @@ I `Main::main` skal vi nå opprette et rutenett, og gi det til `GridView`-konstr
* Grønn i hjørnet nede til høyre (posisjon (2, 3))
* [ ] I `GridView`, legg til en parameter av typen `IColorGrid` i konstruktøren, og legg også til en instansvariabel av samme type. Initialiser feltvariabelen med argumentet gitt til konstruktøren.
For å tegne rutenettet gjenstår det å endre på *paintComponent* -metoden. Vi skal benytte oss av tre hjelpemetoder for å tegne rutenettet:
For å tegne rutenettet gjenstår det å endre på *paintComponent* -metoden. Vi skal benytte oss av tre hjelpemetoder for å tegne rutenettet. I *paintComponent* gjør vi et kall til
* `drawGrid` har som ansvar å tegne et fullstendig rutenett, inkludert alle rammer og ruter (alt innenfor det grå området i illustrasjonen). For å tegne selve rutene, kaller denne metoden på
* `drawGrid`, som har som ansvar å tegne et fullstendig rutenett, inkludert alle rammer og ruter (alt innenfor det grå området i illustrasjonen). For å tegne selve rutene, kaller denne metoden på
* `drawCells`, som har som ansvar å tegne en samling av ruter. For hver rute regner denne metode ut hvor ruten skal være ved å kalle på hjelpemetoden
* `getBoundsForCell` som vet hvordan å regne ut posisjonen til én rute i rutenettet.
Det viser seg at det er den sistnevnte metoden som er mest komplisert. Vi kunne hatt `getBoundForCell` som en vanlig hjelpemetode, men siden dette er en relativt isolert operasjon som vi ønsker å kunne teste separat, oppretter vi en en klasse for denne hjelpemetoden: *CellPositionToPixelConverter*.
> Måten vi tenker på når vi skal utvikle et program er «top-down» -- man begynner med å dele opp oppgaven i store steg, og så drømmer vi opp hjelpemetoder vi trenger før disse hjelpemetodene faktisk eksisterer. Når vi faktisk koder, er det ofte lettest å gjøre det «bottom up», slik at vi kan teste hver enkelt byggeklosse/metode mens vi holder på. Dette for å si: hvilken rekkefølge du løser resten av oppgaven er opp til deg. Det kan være at det er lettere å hoppe litt frem og tilbake mellom de neste avsnittene.
## CellPositionToPixelConverter
......@@ -107,16 +115,16 @@ Disse siste delene med informasjon vil ikke endre seg særlig fra kall til kall,
I klassen `CellPositionToPixelConverter`:
* [ ] Opprett feltvariabler:
* Et `Rectangle2D` -objekt `box` som beskriver innenfor hvilket område rutenettet skal tegnes
* Et `GridDimension` -objekt `gd` som beskriver størrelsen til rutenettet rutene vil være en del av
* [ ] Opprett instansvariabler:
* En `Rectangle2D` -variabel `box` som beskriver innenfor hvilket område rutenettet skal tegnes
* En `GridDimension` -variabel `gd` som beskriver størrelsen til rutenettet rutene vil være en del av
* En `double` kalt `margin` som beskriver hvor stor avstanden skal være mellom rutene
* [ ] Opprett en konstruktør i klassen med tre parametre: et `Rectangle2D` -objekt, et `GridDimension` -objekt og en `double`. Initaliser feltvariablene med verdiene mottat i konstruktøren.
* [ ] Opprett en konstruktør i klassen med tre parametre: en `Rectangle2D` -variabel, en `GridDimension` -variabel og en `double`. Initaliser feltvariablene med argumentene som mottas i konstruktøren.
* [ ] Opprett metoden `getBoundsForCell` med en parameter av typen `CellPosition` (i figur under navgitt `cp`) og returtype `Rectangle2D`.
Returverdien er et `Rectangle2D` -objekt. For å opprette dette objektet, må du regne ut fire verdier: x, y, bredde og høyde for den gitte ruten. Så kan du returnere et nytt `Rectangle2D.Double` -objekt med disse verdiene.
Illustrasjonen under visualiserer parameterne og resultatvariablene. Svarte variabler er gitt som input eller er tilgjengelig som feltvariabler, mens de røde variablene er de du skal regne ut og returnere.
Illustrasjonen under visualiserer parameterne og resultatvariablene. Variabler i svart tekst er gitt som input eller er tilgjengelig som feltvariabler, mens variablene i rød kursiv tekst er de du skal regne ut og returnere.
![Illustrasjon av variabler som opptrer i getBoundsForCell](./img/getBoundsForCell.png)
......@@ -128,13 +136,13 @@ Hint:
> Eksempel: anta at du får følgende parametre (som i illustrasjonen):
> * `box.getX()` er 30 og `box.getY()` er 30
> * `box.getWidth()` er 340 og `box.getHeight()` er 240
> * `cellPosition.col()` er 2 og `cellPosition.row()` er 1
> * `cp.col()` er 2 og `cp.row()` er 1
> * `gd.cols()` er 4 og `gd.rows()` er 3
> * `margin` er 30
>
> Vi begynner med å regne ut `cellWidth`. Siden vi har 4 kolonner totalt, vil det gå med 5*30=150 piksler til marginer, og vi får da 190 piksler igjen å fordele på de fire kolonnene. Vi får da at cellen skal ha bredde 47.5.
>
> For å finne verdien til `cellX` begynner vi på `box.getX()` og legger til margin + rutebredde + margin + rutebredde + margin. Verdien blir da 30+30+47.5+30+47.5+30 = 215.
> For å finne verdien til `cellX` begynner vi på posisjonen `box.getX()` og går derfra videre mot høyre ved å plusse på margin + rutebredde + margin + rutebredde + margin. Verdien blir da 30+30+47.5+30+47.5+30 = 215.
>
> Tilsvarende finner vi at `cellHeight` blir 40 og `cellY` blir 130.
......@@ -156,7 +164,7 @@ Denne metoden i `GridView` skal ha et `Graphics2D` -objekt som parameter, og ikk
PS: Siden metoden benytter instansmetoder kan metoden *ikke* være static. Siden metoden ikke skal benyttes av noen utenfor `GridView` -klassen, bør metoden være *private*.
## drawCell
## drawCells
Denne metoden i `GridView` er uten returverdi, men skal ha tre parametre:
* et `Graphics2D` -objekt, lerretet rutene skal tegnes på
......@@ -167,4 +175,18 @@ La metoden iterere gjennom rutene i CellColorCollection -objektet, og tegne hver
PS: siden drawCells ikke er avhengig av instansvariabler, bør metoden være *static*. Siden den ikke benyttes utenfor `GridCell` -klassen bør metoden være *private*.
✅ Du er ferdig med lab'en når testene i `TestGridView` passerer, og du kan kjøre Main-metoden og ser samme bilde som vist i illustrasjonen nå programmet kjører. Det skal fungere å endre størrelse på vinduet, og rutenettet skal strekke seg for å fylle hele lerretet med en fast avstand til kanten.
\ No newline at end of file
✅ Du er ferdig med lab'en når testene i `TestGridView` passerer, og du kan kjøre Main-metoden og ser samme bilde som vist i illustrasjonen nå programmet kjører. Det skal fungere å endre størrelse på vinduet, og rutenettet skal strekke seg for å fylle hele lerretet med en fast avstand til kanten.
---
## Bonusoppgave
- [ ] La klassen `BeautifulPicture` i pakken `no.uib.inf101.bonus` utvide `JPanel` og tegn en vakker tegning med utgangspunkt i kursnotatene for grafikk. Benytt `Main` -klassen i samme pakke for å starte programmet.
Det blir en liten premie til det peneste bildet. Jury'en legger vekt på:
* at bildet er vakkert, og
* at bildet er *adaptivt*, det vil si: tilpasser seg størrelsen på vinduet på en pen måte, og
* at koden er vakker å lese.
Du er oppfordret til å bruke rikelig med hjelpemetoder og eventuelt også flere klasser som kan hjelpe til med tegningen dersom det er hensiktsmessig.
\ No newline at end of file
package no.uib.inf101.bonus;
public class BeautifulPicture {
// TODO: La klassen utvide JPanel og tegn et vakkert bilde
}
package no.uib.inf101.bonus;
public class Main {
public static void main(String[] args) {
// Kopier inn main-metoden fra kursnotatene om grafikk her,
// men tilpass den slik at du oppretter et BeautifulPicture -objekt
// som lerret.
}
}
package no.uib.inf101.colorgrid;
// Les om records her: https://inf101.ii.uib.no/notat/mutabilitet/#record
import java.awt.Color;
/**
......
package no.uib.inf101.colorgrid;
// Les om records her: https://inf101.ii.uib.no/notat/mutabilitet/#record
/**
* A CellPosition consists of a row and a column.
*
......
......@@ -3,35 +3,55 @@ package no.uib.inf101.colorgrid;
import org.junit.jupiter.api.Test;
import java.awt.Color;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class TestColorGrid {
@Test
public void sanityTest() {
IColorGrid grid = new WColorGrid(3, 4);
// Check that number of rows and cols match up
assertEquals(3, grid.rows());
assertEquals(4, grid.cols());
// Check that default value is null
assertEquals(null, grid.get(new CellPosition(1, 2)));
// Check that we can set a value and retrieve it again
grid.set(new CellPosition(1, 2), Color.RED);
assertEquals(Color.RED, grid.get(new CellPosition(1, 2)));
assertEquals(null, grid.get(new CellPosition(2, 1)));
// Check that we can set a new value and retrieve it again
grid.set(new CellPosition(1, 2), Color.GREEN);
assertEquals(Color.GREEN, grid.get(new CellPosition(1, 2)));
}
@Test
public void testSize() {
IColorGrid grid = createGrid(10, 20);
assertEquals(10, grid.rows());
assertEquals(20, grid.cols());
grid = createGrid(1, 1);
assertEquals(1, grid.rows());
assertEquals(1, grid.cols());
public void testDimension() {
GridDimension gd = new WColorGrid(10, 20);
assertEquals(10, gd.rows());
assertEquals(20, gd.cols());
gd = new WColorGrid(1, 1);
assertEquals(1, gd.rows());
assertEquals(1, gd.cols());
}
@Test
public void testGetDefaultValue() {
IColorGrid grid = createGrid(10, 20);
IColorGrid grid = new WColorGrid(10, 20);
assertNull(grid.get(new CellPosition(0, 0)));
assertNull(grid.get(new CellPosition(2, 3)));
}
@Test
public void testSetGetInCorners() {
IColorGrid grid = createGrid(10, 20);
IColorGrid grid = new WColorGrid(10, 20);
// Set color in corners
grid.set(new CellPosition(0, 0), Color.RED);
grid.set(new CellPosition(0, 19), Color.GREEN);
......@@ -45,9 +65,57 @@ public class TestColorGrid {
assertEquals(Color.YELLOW, grid.get(new CellPosition(9, 19)));
}
@Test
public void testGetCells() {
IColorGrid grid = new WColorGrid(2, 2);
grid.set(new CellPosition(0, 0), Color.RED);
grid.set(new CellPosition(0, 1), Color.GREEN);
grid.set(new CellPosition(1, 0), Color.BLUE);
grid.set(new CellPosition(1, 1), Color.BLACK);
List<CellColor> expected = Arrays.asList(
new CellColor(new CellPosition(0, 0), Color.RED),
new CellColor(new CellPosition(0, 1), Color.GREEN),
new CellColor(new CellPosition(1, 0), Color.BLUE),
new CellColor(new CellPosition(1, 1), Color.BLACK)
);
List<CellColor> actual = grid.getCells();
assertEquals(expected.size(), actual.size());
for (CellColor cp : actual) {
assertTrue(expected.contains(cp));
}
for (CellColor cp : expected) {
assertTrue(actual.contains(cp));
}
}
@Test
public void testGetCellsWithNull() {
IColorGrid grid = new WColorGrid(3, 1);
grid.set(new CellPosition(2, 0), Color.GREEN);
List<CellColor> expected = Arrays.asList(
new CellColor(new CellPosition(0, 0), null),
new CellColor(new CellPosition(1, 0), null),
new CellColor(new CellPosition(2, 0), Color.GREEN)
);
List<CellColor> actual = grid.getCells();
assertEquals(expected.size(), actual.size());
for (CellColor cp : actual) {
assertTrue(expected.contains(cp));
}
for (CellColor cp : expected) {
assertTrue(actual.contains(cp));
}
}
@Test
public void testIndexOutOfBoundsException() {
IColorGrid grid = createGrid(10, 20);
IColorGrid grid = new WColorGrid(10, 20);
// Test out of bounds for get
assertThrows(IndexOutOfBoundsException.class, () -> grid.get(new CellPosition(-1, 0)));
......@@ -61,36 +129,4 @@ public class TestColorGrid {
assertThrows(IndexOutOfBoundsException.class, () -> grid.set(new CellPosition(10, 0), Color.RED));
assertThrows(IndexOutOfBoundsException.class, () -> grid.set(new CellPosition(0, 20), Color.RED));
}
/**
* Create a new ColorGrid with the given rows and cols. This method
* will only work if you have implemented the ColorGrid class with
* the correct parameters (two int's), otherwise the test will fail
* when calling this method.
*
* @param rows number of rows in the colorgrid to create
* @param cols number of columns in the colorgrid to create
* @return a new ColorGrid
*/
public IColorGrid createGrid(int rows, int cols) {
try {
Constructor<?> c = ColorGrid.class.getConstructor(int.class, int.class);
Object o = c.newInstance(rows, cols);
if (o instanceof IColorGrid grid) {
return grid;
}
fail("Constructor did not return an IColorGrid. This could be "
+ "because you forgot to implement the IColorGrid interface.");
} catch (NoSuchMethodException e) {
fail("Could not find constructor ColorGrid(int, int)");
} catch (InvocationTargetException e) {
fail("Constructor crashed: " + e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
fail("Constructor is not public: " + e);
}
return null;
}
}
......@@ -28,7 +28,7 @@ public class TestTextQuestions {
@Test
public void q3() {
assertEquals(false, TextQuestions.a3,
"It is possible to create a class which implements" +
"It is possible to create a class which implements " +
"CellColorCollection directly, without implementing IColorGrid. " +
"Objects in such a class would have the type GridDimension, " +
"but not the type IColorGrid."
......@@ -38,8 +38,8 @@ public class TestTextQuestions {
@Test
public void q4() {
assertEquals(false, TextQuestions.a4,
"It is possible to create a class which implements" +
"GridDimension directly, without implementing IColorGrid or" +
"It is possible to create a class which implements " +
"GridDimension directly, without implementing IColorGrid or " +
"CellColorCollection. Objects in such a class would have the " +
"type GridDimension, but not the type CellColorCollection."
);
......@@ -48,9 +48,9 @@ public class TestTextQuestions {
@Test
public void q5() {
assertEquals(true, TextQuestions.a5,
"If an object has the type IColorGrid, it must indeed" +
"belong to a class that implements the interface IColorGrid." +
"If the class does not do so directly, it must do so" +
"If an object has the type IColorGrid, it must indeed " +
"belong to a class that implements the interface IColorGrid. " +
"If the class does not do so directly, it must do so " +
"indirectly through inheritance."
);
}
......
package no.uib.inf101.colorgrid;
// This class is a "wrapper" around ColorGrid (the class you will
// write). It uses some concepts that are outside the syllabus of
// INF101, and you are not expected to understand the code in the
// createColorGrid method.
//
// We use this class to be able to write the tests in TestColorGrid
// without getting compilation errors, even if ColorGrid is not
// implemented yet. This is done in the context of a scaffolded
// homework assignment, and is not something which is normally seen in
// the wild.
import java.awt.Color;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import static org.junit.jupiter.api.Assertions.fail;
public class WColorGrid implements IColorGrid {
private final IColorGrid cg;
public WColorGrid(int rows, int cols) {
this.cg = newColorGrid(rows, cols);
}
@Override
public List<CellColor> getCells() {
return this.cg.getCells();
}
@Override
public int rows() {
return this.cg.rows();
}
@Override
public int cols() {
return this.cg.cols();
}
@Override
public Color get(CellPosition pos) {
return this.cg.get(pos);
}
@Override
public void set(CellPosition pos, Color color) {
this.cg.set(pos, color);
}
/**
* Create a new ColorGrid with the given rows and cols. This method
* will only work if you have implemented the ColorGrid class with
* the correct parameters (two int's), otherwise the test will fail
* when calling this method.
*
* @param rows number of rows in the colorgrid to create
* @param cols number of columns in the colorgrid to create
* @return a new ColorGrid
*/
private static IColorGrid newColorGrid(int rows, int cols) {
try {
Constructor<?> c = ColorGrid.class.getConstructor(int.class, int.class);
Object o = c.newInstance(rows, cols);
if (o instanceof IColorGrid grid) {
return grid;
}
fail("ColorGrid constructor did not return an IColorGrid. This could "
+ "be because you forgot to implement the IColorGrid interface.");
} catch (NoSuchMethodException e) {
fail("Could not find constructor ColorGrid(int, int)");
} catch (InvocationTargetException e) {
fail("Constructor crashed: " + e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
fail("Constructor is not public: " + e);
}
return null;
}
public static IColorGrid newGridFromStrings(String[] sgrid) {
IColorGrid grid = new WColorGrid(sgrid.length, sgrid[0].length());
for (int r = 0; r < grid.rows(); r++) {
for (int c = 0; c < grid.cols(); c++) {
grid.set(new CellPosition(r, c), switch (sgrid[r].charAt(c)) {
case 'R' -> Color.RED;
case 'G' -> Color.GREEN;
case 'B' -> Color.BLUE;
case 'Y' -> Color.YELLOW;
default -> null;
});
}
}
return grid;
}
}
......@@ -21,20 +21,21 @@ import java.util.Map;
public class RecordGraphics2D extends java.awt.Graphics2D {
private Color color = null;
private final List<Shape> fillRecordShapes = new ArrayList<>();
private final List<Color> fillRecordColors = new ArrayList<>();
private final List<Shape> recordedFillShapes = new ArrayList<>();
private final List<Color> recordedFillColors = new ArrayList<>();
public List<Shape> getFillRecordShapes() {
return this.fillRecordShapes;
public List<Shape> getRecordedFillShapes() {
return this.recordedFillShapes;
}
public List<Color> getFillRecordColors() {
return this.fillRecordColors;
public List<Color> getRecordedFillColors() {
return this.recordedFillColors;
}
public void resetRecord() {
this.fillRecordShapes.clear();
this.fillRecordColors.clear();
@Override
public void fill(Shape s) {
this.recordedFillShapes.add(s);
this.recordedFillColors.add(this.color);
}
@Override
......@@ -42,12 +43,6 @@ public class RecordGraphics2D extends java.awt.Graphics2D {
// dummy ignores
}
@Override
public void fill(Shape s) {
this.fillRecordShapes.add(s);
this.fillRecordColors.add(this.color);
}
@Override
public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
return false;
......@@ -190,7 +185,7 @@ public class RecordGraphics2D extends java.awt.Graphics2D {
@Override
public Color getColor() {
throw new UnsupportedOperationException("Not supported yet.");
return this.color;
}
@Override
......
package no.uib.inf101.gridview;
import no.uib.inf101.colorgrid.CellColor;
import no.uib.inf101.colorgrid.CellPosition;
import no.uib.inf101.colorgrid.GridDimension;
import no.uib.inf101.colorgrid.IColorGrid;
import no.uib.inf101.colorgrid.*;
import org.junit.jupiter.api.Test;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class TestCellPositionToPixelConverter {
@Test
public void illustratedSample() {
IColorGrid grid = newGridFromString(String.join("\n",
"R--B",
"----",
"Y--G")
public void sanityTest() {
// Same case as illustrated in README
// Setup
IColorGrid grid = new WColorGrid(3, 4);
grid.set(new CellPosition(0, 0), Color.RED);
grid.set(new CellPosition(0, 3), Color.BLUE);
grid.set(new CellPosition(2, 0), Color.YELLOW);
grid.set(new CellPosition(2, 3), Color.GREEN);
// Construct CellPositionToPixelConverter (using a wrapper class)
WCellPositionToPixelConverter converter = new WCellPositionToPixelConverter(
new Rectangle2D.Double(30, 30, 340, 240), grid,30
);
CellPositionToPixelConverter converter = getConverter(
grid, new Rectangle2D.Double(30, 30, 340, 240), 30);
// Check result
Rectangle2D expected = new Rectangle2D.Double(215, 130, 47.5, 40);
assertEquals(expected, converter.getBoundsForCell(new CellPosition(1, 2)));
}
/////////////////////////////
// Helper methods
/////////////////////////////
static CellPositionToPixelConverter getConverter(GridDimension grid, Rectangle2D rect, double margin) {
try {
Constructor<?> constructor = CellPositionToPixelConverter.class.getConstructor(
GridDimension.class, Rectangle2D.class, double.class
);
// Check that the constructor is public
assertTrue(Modifier.isPublic(constructor.getModifiers()),
"The constructor CellPositionToPixelConverter(IColorGrid, Rectangle2D, double)"
+ " should be public");
// Create a new object using the constructor and return it
return (CellPositionToPixelConverter) constructor.newInstance(grid, rect, margin);
} catch (NoSuchMethodException e) {
fail("Could not find the constructor CellPositionToPixelConverter(IColorGrid, Rectangle2D, " +
"double) in the CellPositionToPixelConverter class");
} catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
throw new IllegalStateException("Should not be possible to reach this point");
}
static IColorGrid newGridFromString(String stringGrid) {
return new IColorGrid() {
private String[] lines = stringGrid.split("\n");
@Override
public int rows() {
return this.lines.length;
}
@Override
public int cols() {
return this.lines[0].length();
}
@Override
public Color get(CellPosition pos) {
if (pos.row() < 0 || pos.row() >= this.rows()) {
throw new IllegalArgumentException("Row out of bounds");
}
if (pos.col() < 0 || pos.col() >= this.cols()) {
throw new IllegalArgumentException("Column out of bounds");
}
return switch (this.lines[pos.row()].charAt(pos.col())) {
case 'R' -> Color.RED;
case 'G' -> Color.GREEN;
case 'B' -> Color.BLUE;
case 'Y' -> Color.YELLOW;
default -> null;
};
}
@Override
public void set(CellPosition pos, Color color) {
// ignore
}
@Override
public java.util.List<CellColor> getCells() {
List<CellColor> a = new ArrayList<>();
for (int r = 0; r < this.rows(); r++) {
for (int c = 0; c < this.cols(); c++) {
Color color = this.get(new CellPosition(r, c));
a.add(new CellColor(new CellPosition(r, c), color));
}
}
return a;
}
};
}
}
......@@ -16,60 +16,76 @@ import org.junit.jupiter.api.Test;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import static org.junit.jupiter.api.Assertions.*;
public class TestGridView {
@Test
public void preferredSize() {
GridView view = newGridView(null);
assertNotNull(view, "Unable to create a new GridView object");
assertNotNull(view.getPreferredSize(), "PreferredSize should not be null");
public void preferredSizeTest() {
WGridView view = new WGridView(null);
assertNotNull(view.getPreferredSize(), "PreferredSize shouldn't be null");
assertEquals(400, view.getPreferredSize().width);
assertEquals(300, view.getPreferredSize().height);
}
@Test
public void drawCellsIllustratedSample() {
// Sample case from assignment text
IColorGrid sampleGrid = TestCellPositionToPixelConverter.newGridFromString(String.join("\n",
public void drawCellsSanityTest() {
// Sample case illustrated in README
IColorGrid grid = WColorGrid.newGridFromStrings(new String[]{
"R--B",
"----",
"Y--G"
));
});
Rectangle2D box = new Rectangle2D.Double(30, 30, 340, 240);
double margin = 30;
RecordGraphics2D recording = singleDrawCellsRun(grid, box, margin);
// Check that the correct number of calls were filled
assertEquals(12, recording.getRecordedFillShapes().size(),
"The drawCells method call draw 12 rectangles in the illustrated sample case");
assertColorIsDrawnOnceAt(recording, Color.RED, new Rectangle2D.Double(60, 60, 47.5, 40));
assertColorIsDrawnOnceAt(recording, Color.BLUE, new Rectangle2D.Double(292.5, 60, 47.5, 40));
assertColorIsDrawnOnceAt(recording, Color.YELLOW, new Rectangle2D.Double(60, 200, 47.5, 40));
assertColorIsDrawnOnceAt(recording, Color.GREEN, new Rectangle2D.Double(292.5, 200, 47.5, 40));
}
@Test
public void drawCellsSanityOtherColors() {
// Sample case illustrated in README, but colors mixed up
IColorGrid sampleGrid = WColorGrid.newGridFromStrings(new String[]{
"Y--R",
"----",
"G--B"
});
Rectangle2D rect = new Rectangle2D.Double(30, 30, 340, 240);
double margin = 30;
RecordGraphics2D record = singleDrawCellsRun(sampleGrid, rect, margin);
// Check that the correct number of calls were made
assertEquals(12, record.getFillRecordShapes().size(),
"The drawCells method call draw 12 rectangles in the illustrated sample case");
assertEquals(12, record.getRecordedFillShapes().size());
assertColorIsDrawnOnceAt(record, Color.RED, new Rectangle2D.Double(60, 60, 47.5, 40));
assertColorIsDrawnOnceAt(record, Color.BLUE, new Rectangle2D.Double(292.5, 60, 47.5, 40));
assertColorIsDrawnOnceAt(record, Color.YELLOW, new Rectangle2D.Double(60, 200, 47.5, 40));
assertColorIsDrawnOnceAt(record, Color.GREEN, new Rectangle2D.Double(292.5, 200, 47.5, 40));
assertColorIsDrawnOnceAt(record, Color.YELLOW, new Rectangle2D.Double(60, 60, 47.5, 40));
assertColorIsDrawnOnceAt(record, Color.RED, new Rectangle2D.Double(292.5, 60, 47.5, 40));
assertColorIsDrawnOnceAt(record, Color.GREEN, new Rectangle2D.Double(60, 200, 47.5, 40));
assertColorIsDrawnOnceAt(record, Color.BLUE, new Rectangle2D.Double(292.5, 200, 47.5, 40));
}
@Test
public void drawCellsIllustratedSampleTweak() {
public void drawCellsSanityTestPixelsMoved() {
// Sample case from assignment text
IColorGrid sampleGrid = TestCellPositionToPixelConverter.newGridFromString(String.join("\n",
IColorGrid sampleGrid = WColorGrid.newGridFromStrings(new String[]{
"R--B",
"----",
"Y--G"
));
});
Rectangle2D rect = new Rectangle2D.Double(40, 20, 342, 243);
double margin = 30;
RecordGraphics2D record = singleDrawCellsRun(sampleGrid, rect, margin);
// Check that the correct number of calls were made
assertEquals(12, record.getFillRecordShapes().size());
assertEquals(12, record.getRecordedFillShapes().size());
assertColorIsDrawnOnceAt(record, Color.RED, new Rectangle2D.Double(70, 50, 48, 41));
assertColorIsDrawnOnceAt(record, Color.BLUE, new Rectangle2D.Double(304, 50, 48, 41));
......@@ -80,13 +96,13 @@ public class TestGridView {
@Test
public void drawCellsSingleCell() {
// Sample case from assignment text
IColorGrid sampleGrid = TestCellPositionToPixelConverter.newGridFromString("R");
IColorGrid sampleGrid = WColorGrid.newGridFromStrings(new String[] {"R"});
Rectangle2D rect = new Rectangle2D.Double(20, 30, 40, 50);
double margin = 10;
RecordGraphics2D record = singleDrawCellsRun(sampleGrid, rect, margin);
// Check that the correct number of calls were made
assertEquals(1, record.getFillRecordShapes().size());
assertEquals(1, record.getRecordedFillShapes().size());
assertColorIsDrawnOnceAt(record, Color.RED, new Rectangle2D.Double(30, 40, 20, 30));
}
......@@ -96,80 +112,25 @@ public class TestGridView {
private void assertColorIsDrawnOnceAt(RecordGraphics2D record, Color color, Rectangle2D expectedRectangle) {
int count = 0;
for (int i=0; i<record.getFillRecordColors().size(); i++) {
if (record.getFillRecordColors().get(i).equals(color)) {
assertEquals(expectedRectangle, record.getFillRecordShapes().get(i),
for (int i = 0; i<record.getRecordedFillColors().size(); i++) {
if (record.getRecordedFillColors().get(i).equals(color)) {
assertEquals(expectedRectangle, record.getRecordedFillShapes().get(i),
"Incorrect bounds for color "+ color
);
count++;
}
}
assertEquals(1, count, "There should be exactly one rectangle with color "+ color);
}
static GridView newGridView(IColorGrid grid) {
try {
Constructor<?> constructor = GridView.class.getConstructor(IColorGrid.class);
// Check that the constructor is public
assertFalse(Modifier.isPrivate(constructor.getModifiers()),
"The constructor GridView(IColorGrid) should not be private");
// Create a new object using the constructor and return it
return (GridView) constructor.newInstance(grid);
} catch (NoSuchMethodException e) {
if (grid != null) {
fail("Could not find the constructor GridView(IColorGrid) in the GridView class");
}
try {
Constructor<?> constructor = GridView.class.getConstructor();
return (GridView) constructor.newInstance();
} catch (NoSuchMethodException ex) {
fail("Could not find the constructor GridView() or GridView(IColorGrid) in the GridView class");
} catch (InvocationTargetException | InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
} catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
throw new IllegalStateException("Should not be possible to reach this point");
assertEquals(1, count, "There should be exactly one rectangle with color " + color);
}
public static RecordGraphics2D singleDrawCellsRun(
IColorGrid grid, Rectangle2D rect, double margin) {
// Get the "drawCells" method from the GridView class and invoke
// the method with the fake Graphics2D object
try {
Method drawCell = GridView.class.getDeclaredMethod("drawCells",
Graphics2D.class,
CellColorCollection.class,
CellPositionToPixelConverter.class
);
// Test that the method is static
assertTrue(Modifier.isStatic(drawCell.getModifiers()),
"The drawCells method should be static, and it should not use any instance variables");
// Test that the method is private
assertTrue(Modifier.isPrivate(drawCell.getModifiers()),
"The drawCells method should be private");
// Make the method accessible in case it is private
drawCell.setAccessible(true);
// Preparing a "fake" Graphics2D object that records stuff that
// happens to it instead of actually drawing anything
RecordGraphics2D g2 = new RecordGraphics2D();
// Invoke the method
drawCell.invoke(null, g2, grid, TestCellPositionToPixelConverter.getConverter(grid, rect, margin));
return g2;
} catch (NoSuchMethodException e) {
fail("Could not find the method drawCells(Graphics2D, CellColorCollection,"
+ " CellPositionToPixelConverter) in the GridView class");
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
throw new IllegalStateException("Should not reach this point");
RecordGraphics2D g2 = new RecordGraphics2D();
CellPositionToPixelConverter converter = WCellPositionToPixelConverter.newCellPositionToPixelConverter(
rect, grid, margin);
WGridView.drawCells(g2, grid, converter);
return g2;
}
}
package no.uib.inf101.gridview;
// This class is a "wrapper" around CellPositionToPixelConverter (the
// class you will write). It uses some concepts that are outside the
// syllabus of INF101, and you are not expected to understand the code.
//
// We use this class to be able to write the tests in
// TestCellPositionToPixelConverter without getting compilation errors,
// even if CellPositionToPixelConverter is not implemented yet. This is
// done in the context of a scaffolded homework assignment, and is not
// something which is normally seen in the wild.
import no.uib.inf101.colorgrid.CellPosition;
import no.uib.inf101.colorgrid.GridDimension;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
public class WCellPositionToPixelConverter {
CellPositionToPixelConverter converter;
public WCellPositionToPixelConverter(Rectangle2D box, GridDimension gd,
double margin) {
this.converter = newCellPositionToPixelConverter(box, gd, margin);
}
public Rectangle2D getBoundsForCell(CellPosition cp) {
try {
Method method = CellPositionToPixelConverter.class.getDeclaredMethod(
"getBoundsForCell", CellPosition.class);
// Check that the method is public
assertFalse(Modifier.isPrivate(method.getModifiers()),
"The method getBoundsForCell(CellPosition) in the " +
"CellPositionToPixelConverter class should not be private");
Object result = method.invoke(this.converter, cp);
assertInstanceOf(Rectangle2D.class, result,
"The method getBoundsForCell(CellPosition) in the " +
"CellPositionToPixelConverter class should return a " +
"Rectangle2D");
return (Rectangle2D) result;
} catch (NoSuchMethodException e) {
fail("Could not find the method getBoundsForCell(CellPosition) in " +
"the CellPositionToPixelConverter class " + e);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
throw new IllegalStateException("Should not be possible to reach this " +
"point");
}
static CellPositionToPixelConverter newCellPositionToPixelConverter(
Rectangle2D box, GridDimension gd, double margin) {
try {
Constructor<?> constructor = CellPositionToPixelConverter.class
.getConstructor(
Rectangle2D.class, GridDimension.class, double.class);
// Check that the constructor is public
assertTrue(Modifier.isPublic(constructor.getModifiers()),
"The constructor CellPositionToPixelConverter" +
"(Rectangle2D, GridDimension, double) should be public");
// Create a new object using the constructor and return it
return (CellPositionToPixelConverter) constructor.newInstance(box, gd,
margin);
} catch (NoSuchMethodException e) {
fail("Could not find the constructor CellPositionToPixelConverter" +
"(Rectangle2D, GridDimension, double) in the " +
"CellPositionToPixelConverter class");
} catch (InvocationTargetException
| InstantiationException
| IllegalAccessException e) {
throw new RuntimeException(e);
}
throw new IllegalStateException("Shouldn't reach this point");
}
}
package no.uib.inf101.gridview;
// This class is a "wrapper" around GridView (the class you will
// write). It uses some concepts that are outside the syllabus of
// INF101, and you are not expected to understand the code.
//
// We use this class to be able to write the tests in TestGridView
// without getting compilation errors, even if GridView is not
// implemented yet. This is done in the context of a scaffolded
// homework assignment, and is not something which is normally seen in
// the wild.
import no.uib.inf101.colorgrid.CellColorCollection;
import no.uib.inf101.colorgrid.IColorGrid;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import static org.junit.jupiter.api.Assertions.*;
public class WGridView extends JPanel {
private final GridView gv;
private final JPanel jp;
public WGridView(IColorGrid grid) {
GridView gv = WGridView.newGridView(grid);
assertInstanceOf(JPanel.class, gv, "GridView objects does not " +
"carry the type JPanel. Does your GridView class extend JPanel?");
this.gv = gv;
if ((Object) gv instanceof JPanel jp) {
this.jp = jp;
} else {
throw new IllegalStateException("Should not be here");
}
}
@Override
public Dimension getPreferredSize() {
return this.jp.getPreferredSize();
}
static void drawCells(Graphics2D g2, CellColorCollection cells,
CellPositionToPixelConverter converter) {
try {
Method drawCell = GridView.class.getDeclaredMethod("drawCells",
Graphics2D.class,
CellColorCollection.class,
CellPositionToPixelConverter.class
);
// Test that the method is static
assertTrue(Modifier.isStatic(drawCell.getModifiers()),
"The drawCells method should be static, " +
"and it should not use any instance variables");
// Test that the method is private
assertTrue(Modifier.isPrivate(drawCell.getModifiers()),
"The drawCells method should be private");
// Make the method accessible in case it is private
drawCell.setAccessible(true);
// Invoke the method
drawCell.invoke(null, g2, cells, converter);
} catch (NoSuchMethodException e) {
fail("Could not find the method drawCells(Graphics2D, " +
"CellColorCollection, CellPositionToPixelConverter) in the " +
"GridView class");
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private static GridView newGridView(IColorGrid grid) {
try {
Constructor<?> constructor = GridView.class.getConstructor(
IColorGrid.class);
// Check that the constructor is not private
assertFalse(Modifier.isPrivate(constructor.getModifiers()),
"The constructor GridView(IColorGrid) should not " +
"be private");
// Create a new object using the constructor and return it
return (GridView) constructor.newInstance(grid);
} catch (NoSuchMethodException e) {
if (grid != null) {
fail("Could not find the constructor GridView(IColorGrid) in " +
"the GridView class");
}
try {
Constructor<?> constructor = GridView.class.getConstructor();
return (GridView) constructor.newInstance();
} catch (NoSuchMethodException ex) {
fail("Could not find the constructor GridView() or " +
"GridView(IColorGrid) in the GridView class");
} catch (InvocationTargetException
| InstantiationException
| IllegalAccessException ex) {
throw new RuntimeException(ex);
}
} catch (InvocationTargetException
| InstantiationException
| IllegalAccessException e) {
throw new RuntimeException(e);
}
throw new IllegalStateException("Shouldn't reach this point");
}
}