commit d521001dd497fb71fc2c8a670ebc5e78c7f542c6 Author: P Date: Fri Jan 31 14:15:48 2025 +0100 Initial commit diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..1021cae --- /dev/null +++ b/build.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + Builds, tests, and runs the project Playlist. + + + diff --git a/build/built-jar.properties b/build/built-jar.properties new file mode 100644 index 0000000..7b12114 --- /dev/null +++ b/build/built-jar.properties @@ -0,0 +1,4 @@ +#Fri, 31 Jan 2025 01:21:27 +0100 + + +/home/blackilykat/NetbeansProjects/school/Playlist= diff --git a/build/classes/Artista.class b/build/classes/Artista.class new file mode 100644 index 0000000..b8c17e3 Binary files /dev/null and b/build/classes/Artista.class differ diff --git a/build/classes/Brano.class b/build/classes/Brano.class new file mode 100644 index 0000000..acf20af Binary files /dev/null and b/build/classes/Brano.class differ diff --git a/build/classes/Main.class b/build/classes/Main.class new file mode 100644 index 0000000..1b46107 Binary files /dev/null and b/build/classes/Main.class differ diff --git a/build/classes/Playlist$Nodo.class b/build/classes/Playlist$Nodo.class new file mode 100644 index 0000000..9c6fa00 Binary files /dev/null and b/build/classes/Playlist$Nodo.class differ diff --git a/build/classes/Playlist.class b/build/classes/Playlist.class new file mode 100644 index 0000000..517522b Binary files /dev/null and b/build/classes/Playlist.class differ diff --git a/manifest.mf b/manifest.mf new file mode 100644 index 0000000..328e8e5 --- /dev/null +++ b/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml new file mode 100644 index 0000000..807b353 --- /dev/null +++ b/nbproject/build-impl.xml @@ -0,0 +1,1771 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties new file mode 100644 index 0000000..5c402db --- /dev/null +++ b/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=e8bcf82c +build.xml.script.CRC32=63f50820 +build.xml.stylesheet.CRC32=f85dc8f2@1.111.0.48 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=e8bcf82c +nbproject/build-impl.xml.script.CRC32=f108b4e2 +nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.111.0.48 diff --git a/nbproject/private/private.properties b/nbproject/private/private.properties new file mode 100644 index 0000000..82b5a19 --- /dev/null +++ b/nbproject/private/private.properties @@ -0,0 +1,2 @@ +compile.on.save=true +user.properties.file=/home/blackilykat/.netbeans/dev/build.properties diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml new file mode 100644 index 0000000..9fb03d7 --- /dev/null +++ b/nbproject/private/private.xml @@ -0,0 +1,12 @@ + + + + + + file:/home/blackilykat/NetbeansProjects/school/Playlist/src/Playlist.java + file:/home/blackilykat/NetbeansProjects/school/Playlist/src/Brano.java + file:/home/blackilykat/NetbeansProjects/school/Playlist/src/Main.java + file:/home/blackilykat/NetbeansProjects/school/Playlist/src/Artista.java + + + diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 0000000..d68c046 --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,95 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processor.options= +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.modulepath=\ + ${run.modulepath} +debug.test.classpath=\ + ${run.test.classpath} +debug.test.modulepath=\ + ${run.test.modulepath} +# Files in build.classes.dir which should be excluded from distribution jar +dist.archive.excludes= +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/Playlist.jar +dist.javadoc.dir=${dist.dir}/javadoc +dist.jlink.dir=${dist.dir}/jlink +dist.jlink.output=${dist.jlink.dir}/Playlist +excludes= +includes=** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.external.vm=true +javac.modulepath= +javac.processormodulepath= +javac.processorpath=\ + ${javac.classpath} +javac.source=23 +javac.target=23 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.modulepath=\ + ${javac.modulepath} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.html5=false +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +# The jlink additional root modules to resolve +jlink.additionalmodules= +# The jlink additional command line parameters +jlink.additionalparam= +jlink.launcher=true +jlink.launcher.name=Playlist +main.class=Main +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=false +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project. +# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. +# To set system properties for unit tests define test-sys-prop.name=value: +run.jvmargs= +run.modulepath=\ + ${javac.modulepath} +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +run.test.modulepath=\ + ${javac.test.modulepath} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..1eaea94 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,15 @@ + + + org.netbeans.modules.java.j2seproject + + + Playlist + + + + + + + + + diff --git a/src/Artista.java b/src/Artista.java new file mode 100644 index 0000000..fb48dc1 --- /dev/null +++ b/src/Artista.java @@ -0,0 +1,17 @@ +public class Artista { + public final String nome; + public final int annoNascita; + public final String nazionalita; + + public Artista(String nome, int annoNascita, String nazionalita) { + this.nome = nome; + this.annoNascita = annoNascita; + this.nazionalita = nazionalita; + } + + @Override + public String toString() { + // anno di nascita negativo se non si sa + return annoNascita < 0 ? String.format("%s (%s)", nome, nazionalita) : String.format("%s (%d, %s)", nome, annoNascita, nazionalita); + } +} diff --git a/src/Brano.java b/src/Brano.java new file mode 100644 index 0000000..403f724 --- /dev/null +++ b/src/Brano.java @@ -0,0 +1,40 @@ + +import java.util.Arrays; + +public class Brano { + public final String titolo; + public final String genere; + // Durata in secondi + public final int durata; + public final Artista[] artisti; + + public Brano(String titolo, String genere, int minuti, int secondi, Artista... artisti) { + this(titolo, genere, minuti * 60 + secondi, artisti); + } + + public Brano(String titolo, String genere, int durata, Artista... artisti) { + if(artisti.length > 5) { + throw new IllegalArgumentException("Un brano non può avere più di 5 artisti"); + } + if(durata < 0) { + throw new IllegalArgumentException("Un brano non può avere durata negativa"); + } + this.titolo = titolo; + this.genere = genere; + this.durata = durata; + this.artisti = artisti; + } + + @Override + public String toString() { + return String.format( + "(%s, %d:%02d) \"%s\" - %s", + genere, + durata / 60, + durata % 60, + titolo, + String.join(", ", Arrays.stream(artisti).map(artista -> artista.toString()).toList()) + ); + } + +} diff --git a/src/Main.java b/src/Main.java new file mode 100644 index 0000000..5b1b5f3 --- /dev/null +++ b/src/Main.java @@ -0,0 +1,95 @@ +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SpringLayout; + +import java.awt.Container; +import java.awt.Dimension; + +public class Main { + public static void main(String[] args) { + Artista ivycomb = new Artista("ivycomb", 2000, "Canada"); + Artista stephanafro = new Artista("Stephanafro", -1, "USA"); + Brano pennyPinched = new Brano("Penny Pinched", "pop", 2, 15, ivycomb, stephanafro); + Brano vancouver = new Brano("Vancouver", "pop", 3, 42, ivycomb, stephanafro); + Brano terminal18 = new Brano("Terminal 18", "pop", 3, 49, ivycomb, stephanafro); + + Playlist playlist = new Playlist(pennyPinched, vancouver, terminal18); + + Artista caparezza = new Artista("Caparezza", 1973, "Italia"); + Artista diegoPerrone = new Artista("Diego Perrone", 1975, "Italia"); + Brano faiDaTela = new Brano("Fai Da Tela", "hip hop", 3, 59, caparezza, diegoPerrone); + Brano micaVanGogh = new Brano("Mica Van Gogh", "hip hop", 3, 55, caparezza); + Brano nonMeLoPossoPermettere = new Brano("Non me lo posso permettere", "hip hop", 3, 46, caparezza); + + playlist.aggiungiInCoda(faiDaTela); + playlist.aggiungiInCoda(micaVanGogh); + playlist.aggiungiInCoda(nonMeLoPossoPermettere); + + JFrame frame = new JFrame("Playlist"); + frame.setSize(new Dimension(500, 250)); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + SpringLayout layout = new SpringLayout(); + frame.setLayout(layout); + + JLabel testoBranoCorrente = new JLabel(playlist.corrente().toString()); + frame.add(testoBranoCorrente); + + JButton bottoneProssimo = new JButton("Prossimo"); + bottoneProssimo.addActionListener(e -> { + if(e.getSource() != bottoneProssimo) return; + Brano nuovoBrano = playlist.prossimo(); + if(nuovoBrano != null) { + testoBranoCorrente.setText(nuovoBrano.toString()); + } + }); + frame.add(bottoneProssimo); + + JButton bottonePrecedente = new JButton("Precedente"); + bottonePrecedente.addActionListener(e -> { + if(e.getSource() != bottonePrecedente) return; + Brano nuovoBrano = playlist.precedente(); + if(nuovoBrano != null) { + testoBranoCorrente.setText(nuovoBrano.toString()); + } + }); + frame.add(bottonePrecedente); + + JCheckBox opzioneShuffle = new JCheckBox("Shuffle"); + opzioneShuffle.addActionListener(e -> { + if(e.getSource() != opzioneShuffle) return; + playlist.shuffle(opzioneShuffle.isSelected()); + }); + frame.add(opzioneShuffle); + + JCheckBox opzioneRepeat = new JCheckBox("Repeat"); + opzioneRepeat.addActionListener(e -> { + if(e.getSource() != opzioneRepeat) return; + playlist.repeat(opzioneRepeat.isSelected()); + }); + frame.add(opzioneRepeat); + + Container contentPane = frame.getContentPane(); + + layout.putConstraint(SpringLayout.NORTH, testoBranoCorrente, 50, SpringLayout.NORTH, contentPane); + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, testoBranoCorrente, 0, SpringLayout.HORIZONTAL_CENTER, contentPane); + + layout.putConstraint(SpringLayout.NORTH, bottonePrecedente, 20, SpringLayout.SOUTH, testoBranoCorrente); + layout.putConstraint(SpringLayout.EAST, bottonePrecedente, 0, SpringLayout.HORIZONTAL_CENTER, contentPane); + + layout.putConstraint(SpringLayout.NORTH, bottoneProssimo, 0, SpringLayout.NORTH, bottonePrecedente); + layout.putConstraint(SpringLayout.WEST, bottoneProssimo, 0, SpringLayout.EAST, bottonePrecedente); + + layout.putConstraint(SpringLayout.NORTH, opzioneRepeat, 10, SpringLayout.SOUTH, bottonePrecedente); + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, opzioneRepeat, 0, SpringLayout.HORIZONTAL_CENTER, contentPane); + + layout.putConstraint(SpringLayout.NORTH, opzioneShuffle, 10, SpringLayout.SOUTH, opzioneRepeat); + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, opzioneShuffle, 0, SpringLayout.HORIZONTAL_CENTER, contentPane); + + frame.setVisible(true); + } + +} diff --git a/src/Playlist.java b/src/Playlist.java new file mode 100644 index 0000000..bd8ed9e --- /dev/null +++ b/src/Playlist.java @@ -0,0 +1,147 @@ +import java.util.Random; + +public class Playlist { + private Nodo corrente = null; + private Nodo testa = null; + private Nodo coda = null; + private boolean shuffle = false; + private Random random = null; + private Nodo> pilaPrecedenti = null; + private Nodo> pilaProssimi = null; + private int dimensione = 0; + + public Playlist(Brano... brani) { + for(Brano brano : brani) { + if(brano == null) continue; + aggiungiInCoda(brano); + } + } + + public void aggiungiInCoda(Brano brano) { + dimensione++; + if(corrente != null) { + Nodo cursore = corrente; + while(cursore.prossimo != null) cursore = cursore.prossimo; + cursore.prossimo = new Nodo(brano); + cursore.prossimo.precedente = cursore; + coda = cursore.prossimo; + } else { + corrente = new Nodo(brano); + testa = corrente; + coda = corrente; + } + } + + private Nodo branoCasuale() { + Nodo cursore = testa; + if(random == null) random = new Random(); + int pos = random.nextInt(0, dimensione); + for(int i = 0; i < pos; i++) { + cursore = cursore.prossimo; + } + return cursore; + } + + public Brano precedente() { + if(dimensione == 0) return null; + + + if(pilaPrecedenti != null) { + aggiungiInProssimi(corrente); + corrente = pilaPrecedenti.valore; + pilaPrecedenti = pilaPrecedenti.prossimo; + if(pilaPrecedenti != null) { + pilaPrecedenti.precedente = null; + } + return corrente.valore; + } + + if(shuffle) { + aggiungiInProssimi(corrente); + corrente = branoCasuale(); + return corrente.valore; + } + + if(corrente == null || corrente.precedente == null) return null; + aggiungiInProssimi(corrente); + corrente = corrente.precedente; + return corrente.valore; + } + + private void aggiungiInProssimi(Nodo nodo) { + Nodo> nuovoProssimo = new Nodo>(nodo); + if(pilaProssimi != null) { + nuovoProssimo.prossimo = pilaProssimi; + nuovoProssimo.prossimo.precedente = nuovoProssimo; + } + pilaProssimi = nuovoProssimo; + } + + public Brano corrente() { + if(corrente == null) return null; + return corrente.valore; + } + + public Brano prossimo() { + if(dimensione == 0) return null; + + if(pilaProssimi != null) { + aggiungiInPrecedenti(corrente); + corrente = pilaProssimi.valore; + pilaProssimi = pilaProssimi.prossimo; + if(pilaProssimi != null) { + pilaProssimi.precedente = null; + } + return corrente.valore; + } + + if(shuffle) { + aggiungiInPrecedenti(corrente); + corrente = branoCasuale(); + return corrente.valore; + } + + if(corrente == null || corrente.prossimo == null) return null; + aggiungiInPrecedenti(corrente); + corrente = corrente.prossimo; + return corrente.valore; + } + + private void aggiungiInPrecedenti(Nodo nodo) { + Nodo> nuovoPrecedente = new Nodo>(corrente); + if(pilaPrecedenti != null) { + nuovoPrecedente.prossimo = pilaPrecedenti; + nuovoPrecedente.prossimo.precedente = nuovoPrecedente; + } + pilaPrecedenti = nuovoPrecedente; + } + + public void repeat(boolean abilitato) { + // In un contesto reale non modificherei la lista in se ma cambierei la logica solo + // quando devo selezionare la traccia successiva o precedente. Per scopi didattici, + // rendo la lista una lista circolare. + if(abilitato) { + testa.precedente = coda; + coda.prossimo = testa; + } else { + testa.precedente = null; + coda.prossimo = null; + } + System.out.println("Repeat: " + abilitato); + } + + public void shuffle(boolean abilitato) { + shuffle = abilitato; + System.out.println("Shuffle: " + abilitato); + } + + private class Nodo { + public T valore; + public Nodo prossimo; + public Nodo precedente; + + public Nodo(T valore) { + this.valore = valore; + } + } +}