1616import java .util .List ;
1717import java .util .Map ;
1818
19+ /**
20+ * Huvudklass för GUI:t. Hanterar visning av bibliotek, spellistor och sökning.
21+ */
1922public class ItunesPlayList {
2023
24+ // --- DATAMODELLER ---
25+
26+ // En Map som lagrar alla spellistor. Nyckeln är namnet (t.ex. "Musik") och värdet är listan med låtar.
2127 private Map <String , ObservableList <DisplaySong >> allPlaylists = new HashMap <>();
28+
29+ // Listan med namn på spellistor som visas i vänstermenyn (Sidebar).
30+ // "ObservableList" gör att GUI:t uppdateras automatiskt om vi lägger till/tar bort namn här.
2231 private ObservableList <String > playlistNames = FXCollections .observableArrayList ();
32+
33+ // --- GUI KOMPONENTER ---
34+
35+ // Tabellen i mitten som visar låtarna
2336 private TableView <DisplaySong > songTable = new TableView <>();
37+
38+ // Listan till vänster där man väljer spellista
2439 private ListView <String > sourceList = new ListView <>();
25- private Text lcdTitle = new Text ("iTunes" );
40+
41+ // Textfält för den "digitala displayen" högst upp
42+ private Text lcdTitle = new Text ("myTunes" );
2643 private Text lcdArtist = new Text ("Välj bibliotek eller spellista" );
2744
45+ /**
46+ * Bygger upp hela gränssnittet och visar fönstret.
47+ * @param dbSongs En lista med låtar hämtade från databasen/backend.
48+ */
2849 public void showLibrary (List <org .example .entity .Song > dbSongs ) {
2950 Stage stage = new Stage ();
51+
52+ // Konvertera databas-objekten till vår interna DisplaySong-klass och skapa grundlistorna
3053 initData (dbSongs );
54+
55+ // BorderPane är huvudlayouten: Top, Left, Center, Bottom
3156 BorderPane root = new BorderPane ();
3257
33- // --- TOPPEN ---
34- HBox topPanel = new HBox (15 );
35- topPanel .getStyleClass ().add ("top-panel" );
58+ // ---------------------------------------------------------
59+ // 1. TOPPEN (Knappar, LCD-display, Sökfält)
60+ // ---------------------------------------------------------
61+ HBox topPanel = new HBox (15 ); // HBox lägger saker på rad horisontellt
62+ topPanel .getStyleClass ().add ("top-panel" ); // CSS-klass för styling
3663 topPanel .setPadding (new Insets (10 , 15 , 10 , 15 ));
3764 topPanel .setAlignment (Pos .CENTER_LEFT );
3865
66+ // Skapa LCD-displayen (den blå rutan med text)
3967 StackPane lcdDisplay = createLCDDisplay ();
68+ // Säg åt displayen att växa och ta upp ledig plats i bredd
4069 HBox .setHgrow (lcdDisplay , Priority .ALWAYS );
4170
71+ // Sökfältet
4272 TextField searchField = new TextField ();
4373 searchField .setPromptText ("Sök..." );
4474 searchField .getStyleClass ().add ("itunes-search" );
75+
76+ // Lyssnare: När texten ändras i sökfältet, kör metoden filterSongs()
4577 searchField .textProperty ().addListener ((obs , old , newVal ) -> filterSongs (newVal ));
4678
79+ // Lägg till allt i toppen
4780 topPanel .getChildren ().addAll (
4881 createRoundButton ("⏮" ), createRoundButton ("▶" ), createRoundButton ("⏭" ),
4982 lcdDisplay , searchField
5083 );
5184
52- // --- VÄNSTER ---
53- sourceList .setItems (playlistNames );
85+ // ---------------------------------------------------------
86+ // 2. VÄNSTER (Spellistorna)
87+ // ---------------------------------------------------------
88+ sourceList .setItems (playlistNames ); // Koppla data till listan
5489 sourceList .getStyleClass ().add ("source-list" );
5590 sourceList .setPrefWidth (200 );
91+
92+ // Lyssnare: Vad händer när man klickar på en spellista i menyn?
5693 sourceList .getSelectionModel ().selectedItemProperty ().addListener ((obs , old , newVal ) -> {
5794 if (newVal != null ) {
58- searchField .clear ();
95+ searchField .clear (); // Rensa gammal sökning
96+ // Hämta låtlistan från vår Map baserat på namnet och visa i tabellen
5997 songTable .setItems (allPlaylists .get (newVal ));
6098 }
6199 });
62- sourceList .getSelectionModel ().selectFirst ();
100+ sourceList .getSelectionModel ().selectFirst (); // Välj första listan ("Musik") som startvärde
63101
64- // --- MITTEN ---
65- setupTable ();
102+ // ---------------------------------------------------------
103+ // 3. MITTEN (Låttabellen)
104+ // ---------------------------------------------------------
105+ setupTable (); // Konfigurerar kolumner och beteende för tabellen
66106
67- // --- BOTTEN ---
107+ // ---------------------------------------------------------
108+ // 4. BOTTEN (Knappar för att hantera listor)
109+ // ---------------------------------------------------------
68110 HBox bottomPanel = new HBox (10 );
69111 bottomPanel .setPadding (new Insets (10 ));
70112 bottomPanel .getStyleClass ().add ("bottom-panel" );
@@ -76,28 +118,38 @@ public void showLibrary(List<org.example.entity.Song> dbSongs) {
76118 Button btnMoveToPlaylist = new Button ("Lägg till Låt i spellista" );
77119 Button btnRemoveSong = new Button ("Ta bort låt från lista" );
78120
121+ // Koppla knapparna till metoder
79122 btnAddList .setOnAction (e -> createNewPlaylist ());
80123 btnDeleteList .setOnAction (e -> deleteSelectedPlaylist ());
81124 btnRemoveSong .setOnAction (e -> removeSelectedSong ());
82- btnMoveToPlaylist .setOnAction (e -> showMoveToMenu (btnMoveToPlaylist ));
125+ btnMoveToPlaylist .setOnAction (e -> addSelectedSong (btnMoveToPlaylist ));
83126
84127 bottomPanel .getChildren ().addAll (btnAddList , btnDeleteList , new Separator (), btnMoveToPlaylist , btnRemoveSong );
85128
129+ // ---------------------------------------------------------
130+ // SLUTMONTERING
131+ // ---------------------------------------------------------
132+
133+ // SplitPane gör att användaren kan dra i gränsen mellan vänstermeny och tabell
86134 SplitPane splitPane = new SplitPane (sourceList , songTable );
87- splitPane .setDividerPositions (0.25 );
135+ splitPane .setDividerPositions (0.25 ); // Sätt startposition för avdelaren
88136
89137 root .setTop (topPanel );
90138 root .setCenter (splitPane );
91139 root .setBottom (bottomPanel );
92140
93141 Scene scene = new Scene (root , 950 , 600 );
142+ // Ladda CSS-filen (måste ligga i resources-mappen)
94143 scene .getStylesheets ().add (getClass ().getResource ("/ipod_style.css" ).toExternalForm ());
95144
96145 stage .setScene (scene );
97146 stage .setTitle ("myTunes" );
98147 stage .show ();
99148 }
100149
150+ /**
151+ * Hjälpmetod för att skapa LCD-displayen (bakgrund + text).
152+ */
101153 private StackPane createLCDDisplay () {
102154 StackPane stack = new StackPane ();
103155 Rectangle bg = new Rectangle (350 , 45 );
@@ -113,25 +165,40 @@ private StackPane createLCDDisplay() {
113165 return stack ;
114166 }
115167
168+ /**
169+ * Hjälpmetod för att skapa en standardiserad knapp.
170+ */
116171 private Button createRoundButton (String icon ) {
117172 Button b = new Button (icon );
118173 b .getStyleClass ().add ("itunes-button" );
119174 return b ;
120175 }
121176
177+ /**
178+ * Konfigurerar kolumnerna i tabellen och hur data ska visas.
179+ */
122180 private void setupTable () {
181+ // Skapa kolumner
123182 TableColumn <DisplaySong , String > titleCol = new TableColumn <>("Namn" );
183+ // Berätta för kolumnen vilket fält i DisplaySong den ska läsa från (name)
124184 titleCol .setCellValueFactory (d -> new SimpleStringProperty (d .getValue ().name ));
185+
125186 TableColumn <DisplaySong , String > artistCol = new TableColumn <>("Artist" );
126187 artistCol .setCellValueFactory (d -> new SimpleStringProperty (d .getValue ().artist ));
188+
127189 TableColumn <DisplaySong , String > albumCol = new TableColumn <>("Album" );
128190 albumCol .setCellValueFactory (d -> new SimpleStringProperty (d .getValue ().album ));
191+
129192 TableColumn <DisplaySong , String > timeCol = new TableColumn <>("Längd" );
130193 timeCol .setCellValueFactory (d -> new SimpleStringProperty (d .getValue ().time ));
131194
132195 songTable .getColumns ().setAll (titleCol , artistCol , albumCol , timeCol );
133196 songTable .getStyleClass ().add ("song-table" );
197+
198+ // Gör så att kolumnerna fyller ut hela bredden
134199 songTable .setColumnResizePolicy (TableView .CONSTRAINED_RESIZE_POLICY );
200+
201+ // Lyssnare: När man klickar på en rad i tabellen -> Uppdatera LCD-displayen
135202 songTable .getSelectionModel ().selectedItemProperty ().addListener ((obs , old , newVal ) -> {
136203 if (newVal != null ) {
137204 lcdTitle .setText (newVal .name );
@@ -140,46 +207,84 @@ private void setupTable() {
140207 });
141208 }
142209
210+ /**
211+ * Filtrerar låtarna i den aktiva listan baserat på söktexten.
212+ */
143213 private void filterSongs (String searchText ) {
144214 String currentList = sourceList .getSelectionModel ().getSelectedItem ();
145215 if (currentList == null ) return ;
216+
217+ // Hämta originaldatan för den valda spellistan
146218 ObservableList <DisplaySong > masterData = allPlaylists .get (currentList );
219+
220+ // Om sökfältet är tomt, visa allt
147221 if (searchText == null || searchText .isEmpty ()) {
148222 songTable .setItems (masterData );
149223 return ;
150224 }
225+
226+ // Skapa en filtrerad lista som omsluter masterData
151227 FilteredList <DisplaySong > filteredData = new FilteredList <>(masterData , song -> {
152228 String filter = searchText .toLowerCase ();
153- return song .name .toLowerCase ().contains (filter ) || song .artist .toLowerCase ().contains (filter ) || song .album .toLowerCase ().contains (filter );
229+ // Returnera true om sökordet finns i namn, artist eller album
230+ return song .name .toLowerCase ().contains (filter ) ||
231+ song .artist .toLowerCase ().contains (filter ) ||
232+ song .album .toLowerCase ().contains (filter );
154233 });
234+
155235 songTable .setItems (filteredData );
156236 }
157237
238+ /**
239+ * Omvandlar databas-objekten till GUI-objekt och skapar standardlistor.
240+ */
158241 private void initData (List <org .example .entity .Song > dbSongs ) {
159242 ObservableList <DisplaySong > library = FXCollections .observableArrayList ();
243+
244+ // Loopa igenom datan från databasen
160245 if (dbSongs != null ) {
161246 for (org .example .entity .Song s : dbSongs ) {
247+ // Hantera null-värden snyggt (om artist eller album saknas)
162248 String art = (s .getAlbum () != null && s .getAlbum ().getArtist () != null ) ? s .getAlbum ().getArtist ().getName () : "Okänd" ;
163249 String alb = (s .getAlbum () != null ) ? s .getAlbum ().getName () : "Okänt" ;
250+
251+ // Skapa ett nytt DisplaySong-objekt
164252 library .add (new DisplaySong (s .getTitle (), art , alb , s .getLength ()));
165253 }
166254 }
255+
256+ // Lägg in huvudbiblioteket "Musik"
167257 allPlaylists .put ("Musik" , library );
168258 playlistNames .add ("Musik" );
259+
260+ // Skapa en tom lista för "Favoriter"
169261 allPlaylists .put ("Favoriter" , FXCollections .observableArrayList ());
170262 playlistNames .add ("Favoriter" );
171263 }
172264
265+ /**
266+ * Visar en dialogruta för att skapa en ny spellista.
267+ */
173268 private void createNewPlaylist () {
174269 TextInputDialog d = new TextInputDialog ("Ny lista" );
270+
271+ // Här ändrar du fönstrets titel och text
272+ d .setTitle ("Skapa ny spellista" ); // Ersätter "Bekräftelse"
273+ d .setHeaderText ("Ange namn på din nya lista" ); // Rubriken inuti rutan
274+ d .setContentText ("Namn:" ); // Texten bredvid inmatningsfältet
275+
175276 d .showAndWait ().ifPresent (name -> {
277+ // Kontrollera att namnet inte är tomt och inte redan finns
176278 if (!name .trim ().isEmpty () && !allPlaylists .containsKey (name )) {
177279 allPlaylists .put (name , FXCollections .observableArrayList ());
178280 playlistNames .add (name );
179281 }
180282 });
181283 }
182284
285+ /**
286+ * Tar bort vald spellista (men tillåter inte att man tar bort "Musik").
287+ */
183288 private void deleteSelectedPlaylist () {
184289 String sel = sourceList .getSelectionModel ().getSelectedItem ();
185290 if (sel != null && !sel .equals ("Musik" )) {
@@ -188,29 +293,53 @@ private void deleteSelectedPlaylist() {
188293 }
189294 }
190295
296+ /**
297+ * Tar bort vald låt från den aktiva spellistan (ej från huvudbiblioteket "Musik").
298+ */
191299 private void removeSelectedSong () {
192300 DisplaySong sel = songTable .getSelectionModel ().getSelectedItem ();
193301 String list = sourceList .getSelectionModel ().getSelectedItem ();
194- if (sel != null && list != null && !list .equals ("Musik" )) allPlaylists .get (list ).remove (sel );
302+ // Skydd: Man får inte ta bort låtar direkt från "Musik"-biblioteket i denna vy
303+ if (sel != null && list != null && !list .equals ("Musik" )) {
304+ allPlaylists .get (list ).remove (sel );
305+ }
195306 }
196307
197- private void showMoveToMenu (Button anchor ) {
308+ /**
309+ * Visar en popup-meny för att lägga till vald låt i en annan spellista.
310+ */
311+ private void addSelectedSong (Button anchor ) {
198312 DisplaySong sel = songTable .getSelectionModel ().getSelectedItem ();
199- if (sel == null ) return ;
313+ if (sel == null ) return ; // Ingen låt vald
314+
200315 ContextMenu menu = new ContextMenu ();
201316 for (String n : playlistNames ) {
202- if (n .equals ("Musik" )) continue ;
317+ if (n .equals ("Musik" )) continue ; // Man kan inte lägga till i "Musik" (det är källan)
318+
203319 MenuItem itm = new MenuItem (n );
204- itm .setOnAction (e -> { if (!allPlaylists .get (n ).contains (sel )) allPlaylists .get (n ).add (sel ); });
320+ itm .setOnAction (e -> {
321+ // Om låten inte redan finns i listan, lägg till den
322+ if (!allPlaylists .get (n ).contains (sel )) {
323+ allPlaylists .get (n ).add (sel );
324+ }
325+ });
205326 menu .getItems ().add (itm );
206327 }
328+ // Visa menyn vid knappen
207329 menu .show (anchor , anchor .getScene ().getWindow ().getX () + anchor .getLayoutX (), anchor .getScene ().getWindow ().getY () + anchor .getLayoutY ());
208330 }
209331
332+ /**
333+ * En inre klass (DTO - Data Transfer Object) enbart för visning i tabellen.
334+ * Detta skiljer GUI-logiken från databas-entiteterna.
335+ */
210336 public static class DisplaySong {
211337 String name , artist , album , time ;
212338 public DisplaySong (String n , String a , String al , Long t ) {
213- this .name = n ; this .artist = a ; this .album = al ; this .time = String .valueOf (t );
339+ this .name = n ;
340+ this .artist = a ;
341+ this .album = al ;
342+ this .time = String .valueOf (t );
214343 }
215344 }
216345}
0 commit comments