package view; import controller.PhotoAlbumController; import model.Photo; import model.PhotoAlbumModel; import javax.swing.*; import java.awt.*; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A view that displays a photo album user interface. *
* This class is responsible for displaying the photo album's graphical interface, * including the list of photos, current photo display, and control buttons. * The view implements the {@link PhotoAlbumModel.ModelChangeListener} interface * to receive notifications of model changes. *
* The view provides user interface components for: *
* Sets up the frame properties, creates buttons, list components, * and initializes them with default states. */ private void initializeComponents() { setTitle("Photo Album Manager"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(800, 600); listModel = new DefaultListModel<>(); photoList = new JList<>(listModel); currentPhotoLabel = new JLabel("No photo selected", SwingConstants.CENTER); addButton = new JButton("Add Photo"); deleteButton = new JButton("Delete Photo"); previousButton = new JButton("Previous"); nextButton = new JButton("Next"); // Disable navigation buttons by default previousButton.setEnabled(false); nextButton.setEnabled(false); deleteButton.setEnabled(false); String[] sortOptions = {"Sort by Name", "Sort by Date", "Sort by Size"}; sortingCombo = new JComboBox<>(sortOptions); listModel = new DefaultListModel<>(); photoList = new JList<>(listModel); photoList.setEnabled(false); photoList.setCellRenderer(new PhotoListCellRenderer()); photoList.setFixedCellHeight(60); // Accommodate thumbnails } /** * Sets up the layout of the photo album view. *
* Arranges the UI components using BorderLayout with: *
* Attaches the controller to the view and sets up event listeners * for the control buttons and sorting combo box. * * @param controller the controller to set */ public void setController(PhotoAlbumController controller) { this.model = controller.getModel(); model.addListener(this); addButton.addActionListener(e -> controller.handleAddPhoto()); deleteButton.addActionListener(e -> controller.handleDeletePhoto()); nextButton.addActionListener(e -> controller.handleNext()); previousButton.addActionListener(e -> controller.handlePrevious()); sortingCombo.addActionListener(e -> controller.handleSort(sortingCombo.getSelectedIndex())); // Select default sorting option sortingCombo.setSelectedIndex(1); } @Override public void onModelChanged() { updatePhotoList(); updateCurrentPhoto(); updateNavigationButtons(); } /** * Updates the list of photos displayed in the sidebar. *
* Clears the current list model and populates it with
* names of photos from the model.
*/
private void updatePhotoList() {
listModel.clear();
List
* If a photo is selected, loads and displays its image.
* If loading fails, displays an error message.
* If no photo is selected, displays a default message.
*/
private void updateCurrentPhoto() {
Photo current = model.getCurrentPhoto();
if (current != null) {
ImageIcon icon = loadImage(current.filePath());
if (icon != null) {
currentPhotoLabel.setIcon(icon);
currentPhotoLabel.setText("");
} else {
currentPhotoLabel.setIcon(null);
currentPhotoLabel.setText("Unable to load image");
}
} else {
currentPhotoLabel.setIcon(null);
currentPhotoLabel.setText("No photo selected");
}
}
/**
* Updates the enabled state of navigation buttons.
*
* Enables or disables the previous/next buttons based on
* the current position in the photo album.
* Enables the delete button only when the album is not empty.
*/
private void updateNavigationButtons() {
previousButton.setEnabled(model.hasPrevious());
nextButton.setEnabled(model.hasNext());
deleteButton.setEnabled(model.getCurrentPhoto() != null);
}
/**
* Loads and scales an image from the given path.
*
* Creates a scaled version of the image suitable for the main display area.
*
* @param path the file path of the image to load
* @return a scaled ImageIcon, or null if loading fails
*/
private ImageIcon loadImage(String path) {
try {
ImageIcon icon = new ImageIcon(path);
Image img = icon.getImage();
Image scaledImg = img.getScaledInstance(400, 300, Image.SCALE_SMOOTH);
return new ImageIcon(scaledImg);
} catch (Exception e) {
return null;
}
}
/**
* A custom list cell renderer for displaying photos with thumbnails and details.
*
* This inner class renders each photo in the list with:
*
* It also implements thumbnail caching to improve performance.
*/
private class PhotoListCellRenderer extends JPanel implements ListCellRenderer
* Converts the size to kilobytes or megabytes with one decimal place.
*
* @param size the file size in bytes
* @return a formatted string with the size in KB or MB
*/
private String formatFileSize(long size) {
if (size < 1024 * 1024) {
return String.format("%.1f KB", size / 1024.0);
} else {
return String.format("%.1f MB", size / (1024.0 * 1024));
}
}
/**
* Loads and scales a thumbnail image from the given path.
*
* Creates a scaled version of the image suitable for the list display.
*
* @param path the file path of the image to load
* @return a scaled ImageIcon, or null if loading fails
*/
private ImageIcon loadThumbnail(String path) {
try {
ImageIcon icon = new ImageIcon(path);
Image img = icon.getImage();
Image scaledImg = img.getScaledInstance(50, 50, Image.SCALE_AREA_AVERAGING);
return new ImageIcon(scaledImg);
} catch (Exception e) {
return null;
}
}
}
}
*
*