From: Sergej Pavlenko Date: Thu, 20 Nov 2025 14:03:58 +0000 (+0100) Subject: Overview Tab erstellt für die Tankstellen und deren Treibstoffe und Preise X-Git-Url: https://git.eternal.ddnss.de/?a=commitdiff_plain;h=636807d11e7356d0f65ab8a80cf5300c2915dbfb;p=tankstelle.git Overview Tab erstellt für die Tankstellen und deren Treibstoffe und Preise --- 636807d11e7356d0f65ab8a80cf5300c2915dbfb diff --cc src/main/java/de/diejungsvondertanke/tankstelle/FuelStationUI.java index 553c790,0000000..02a8676 mode 100644,000000..100644 --- a/src/main/java/de/diejungsvondertanke/tankstelle/FuelStationUI.java +++ b/src/main/java/de/diejungsvondertanke/tankstelle/FuelStationUI.java @@@ -1,499 -1,0 +1,583 @@@ +package de.diejungsvondertanke.tankstelle; + +import de.diejungsvondertanke.tankstelle.error.NoSuchFuelTypeError; + +import javax.swing.*; ++import javax.swing.table.DefaultTableModel; +import java.awt.*; +import java.util.List; + +/** + * GUI for fuel stations + * + * @author Sergej Pavlenko + */ +public class FuelStationUI extends JFrame { + + private JComboBox comboFuelStations; + private JComboBox comboFuelTypes; + private JTextArea outputArea; + private JPanel contentPane; + private JList listFuelStations; ++ private JTable tableFuelTypesPerStation; ++ private javax.swing.table.DefaultTableModel fuelTableModel; + + public FuelStationUI() { + setContentPane(contentPane); + setTitle("Fuel Station Management System"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(800, 600); + setLocationRelativeTo(null); + + initComponents(); + } + + /** + * Layout for GUI + * + * @author Sergej Pavlenko + */ + private void initComponents() { + setLayout(new BorderLayout()); + + JPanel selectionPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + + comboFuelStations = new JComboBox<>(buildStationNames()); + comboFuelTypes = new JComboBox<>(FuelType.values()); + + listFuelStations = new JList<>(); + listFuelStations.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + + refreshStationNames(); + + selectionPanel.add(new JLabel("Fuel station:")); + selectionPanel.add(comboFuelStations); + selectionPanel.add(new JLabel("Fuel type:")); + selectionPanel.add(comboFuelTypes); + + add(selectionPanel, BorderLayout.NORTH); + + JTabbedPane tabbedPane = new JTabbedPane(); + tabbedPane.addTab("Result", createResultPanel()); + tabbedPane.addTab("Change price", createPricePanel()); + tabbedPane.addTab("Change stock", createStockPanel()); + tabbedPane.addTab("Search", createSearchPanel()); + tabbedPane.addTab("New fuel station", createNewFuelStationPanel()); ++ tabbedPane.addTab("Overview", createOverviewPanel()); + + add(tabbedPane, BorderLayout.CENTER); + + outputArea = new JTextArea(); + outputArea.setEditable(false); + outputArea.setLineWrap(true); + outputArea.setWrapStyleWord(true); + JScrollPane scrollPane = new JScrollPane(outputArea); + scrollPane.setPreferredSize(new Dimension(800, 150)); + add(scrollPane, BorderLayout.SOUTH); + } + + /** + * Creates names for the fuel stations + * + * @return fuel station names + * + * @author Sergej Pavlenko + */ + private String[] buildStationNames() { + List stations = Main.fuelStations; + String[] names = new String[stations.size()]; + for (int i = 0; i < stations.size(); i++) { + FuelStation fs = stations.get(i); + String typeName = fs.getClass().getSimpleName(); + names[i] = "Station " + (i + 1) + " (" + typeName + ")"; + } + return names; + } + + /** + * Getter method + * + * @return selected fuel station + * + * @author Sergej Pavlenko + */ + private FuelStation getSelectedStation() { + int idx = comboFuelStations.getSelectedIndex(); + if (idx < 0 || idx >= Main.fuelStations.size()) { + return null; + } + return Main.fuelStations.get(idx); + } + + /** + * Create Panel for results of arithmetic operations + * + * @return result panel + * + * @author Sergej Pavlenko + */ + private JPanel createResultPanel() { + JPanel panel = new JPanel(new BorderLayout()); + + JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 5, 5)); + + JButton btnTotalPrice = new JButton("Total selling value of all available fuel types"); + btnTotalPrice.addActionListener(e -> { + float sum = 0f; + for (FuelStation station : Main.fuelStations) { + sum += station.get_cumulative_retail_price(); + } + appendOutput(String.format( + "Total selling value of all available fuel types: %.2f €", sum)); + }); + + JButton btnHighestPrice = new JButton("Fuel station with highest price (chosen fuel type)"); + btnHighestPrice.addActionListener(e -> { + FuelType type = (FuelType) comboFuelTypes.getSelectedItem(); + try { + FuelStation fs = Main.getHighestPrice(type); + appendOutput("Fuel station with highest price for " + type + ": " + + getDisplayName(fs)); + } catch (NoSuchFuelTypeError ex) { + showError("No fitting fuel station with chosen fuel type " + type + " found."); + } + }); + + JButton btnHighestTotalValue = new JButton("Fuel station with highest total value of all available fuel types"); + btnHighestTotalValue.addActionListener(e -> { + try { + FuelStation fs = Main.getHighestAccumulatedValue(); + appendOutput("Fuel station with highest total value of all available fuel types: " + + getDisplayName(fs)); + } catch (NoSuchFuelTypeError ex) { + showError("Error when calculating highest total value."); + } + }); + + JButton btnStock = new JButton("Highest / lowest stock (chosen fuel type)"); + btnStock.addActionListener(e -> { + FuelType type = (FuelType) comboFuelTypes.getSelectedItem(); + try { + FuelStation max = Main.getHighestStoredAmount(type); + FuelStation min = Main.getLowestStoredAmount(type); + appendOutput("For fuel type " + type + ":\n" + + " Highest stock: " + getDisplayName(max) + "\n" + + " Lowest stock: " + getDisplayName(min)); + } catch (NoSuchFuelTypeError ex) { + showError("No fitting fuel station with fuel type " + type + " found."); + } + }); + + JButton btnTotalStock = new JButton("Total stock (chosen fuel station, chosen fuel type)"); + btnTotalStock.addActionListener(e -> { + FuelType type = (FuelType) comboFuelTypes.getSelectedItem(); + int[] indices = listFuelStations.getSelectedIndices(); + + if (indices.length == 0) { + showError("Please select at least one fuel station."); + return; + } + + FuelStation[] selectedStations = new FuelStation[indices.length]; + for (int i = 0; i < indices.length; i++) { + selectedStations[i] = Main.fuelStations.get(indices[i]); + } + + float total = Main.getTotalStockLevelOfFuel(type, selectedStations); + appendOutput(String.format("Total stock of %s across %d chosen fuel stations: %.2f L", type, indices.length, total)); + }); + + buttonPanel.add(btnTotalPrice); + buttonPanel.add(btnHighestPrice); + buttonPanel.add(btnHighestTotalValue); + buttonPanel.add(btnStock); + buttonPanel.add(btnTotalStock); + + JScrollPane listScroller = new JScrollPane(listFuelStations); + listScroller.setPreferredSize(new Dimension(250, 0)); + + JPanel listPanel = new JPanel(new BorderLayout()); + listPanel.add(new JLabel("Fuel station selection (multiple possible):"), BorderLayout.NORTH); + listPanel.add(listFuelStations, BorderLayout.CENTER); + + panel.add(buttonPanel, BorderLayout.CENTER); + panel.add(listScroller, BorderLayout.EAST); + panel.add(listPanel, BorderLayout.EAST); + + return panel; + } + + /** + * Create Panel for price changing + * + * @return price changing Panel + * + * @author Sergej Pavlenko + */ + private JPanel createPricePanel() { + JPanel panel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5,5,5,5); + gbc.fill = GridBagConstraints.HORIZONTAL; + + JLabel lblPrice = new JLabel("New price per litre (€):"); + JTextField txtPrice = new JTextField(10); + JButton btnSave = new JButton("Change price"); + + btnSave.addActionListener(e -> { + FuelStation station = getSelectedStation(); + FuelType type = (FuelType) comboFuelTypes.getSelectedItem(); + if (station == null) { + showError("No fuel station chosen."); + return; + } + try { + float newPrice = Float.parseFloat(txtPrice.getText().replace(",", ".")); + station.set_price(type, newPrice); + appendOutput(String.format( + "Price changed of %s at %s to %.3f €/L.", + type, getDisplayName(station), newPrice + )); + txtPrice.setText(""); + } catch (NumberFormatException ex) { + showError("Please enter a valid number for the price."); + } catch (NoSuchFuelTypeError ex) { + showError("This fuel station does not offer the fuel type " + type); + } + }); + + gbc.gridx = 0; gbc.gridy = 0; + panel.add(lblPrice, gbc); + gbc.gridx = 1; + panel.add(txtPrice, gbc); + + gbc.gridx = 0; gbc.gridy = 1; gbc.gridwidth = 2; + panel.add(btnSave, gbc); + + return panel; + } + + /** + * Create Panel to change stock + * + * @author Sergej Pavlenko + */ + private JPanel createStockPanel() { + JPanel panel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5,5,5,5); + gbc.fill = GridBagConstraints.HORIZONTAL; + + JLabel lblAmount = new JLabel("Amount (litre):"); + JTextField txtAmount = new JTextField(10); + JRadioButton rbAbsolute = new JRadioButton("Set absolute amount", true); + JRadioButton rbDelta = new JRadioButton("Change amount (+/-)"); + ButtonGroup group = new ButtonGroup(); + group.add(rbAbsolute); + group.add(rbDelta); + + JButton btnSave = new JButton("Change stock"); + + btnSave.addActionListener(e -> { + FuelStation station = getSelectedStation(); + FuelType type = (FuelType) comboFuelTypes.getSelectedItem(); + if (station == null) { + showError("No fuel station chosen."); + return; + } + try { + float value = Float.parseFloat(txtAmount.getText().replace(",", ".")); + int capacity = getCapacity(station, type); + float current = station.getStored_amount(type); + + if (rbAbsolute.isSelected()) { + if (value < 0) { + showError("Please enter a positive number"); + return; + } + if (value > capacity) { + showError("Maximum capacity of " + capacity + " L is being crossed."); + return; + } + station.set_stored_amount(value, type); + appendOutput(String.format( + "Changed stock of %s at %s to %.2f litre.", + type, getDisplayName(station), value + )); + txtAmount.setText(""); + } else { + float updated = current + value; + if (updated < 0) { + showError("The amount of fuel may not be negative."); + return; + } + if (updated > capacity) { + showError("Maximum capacity of " + capacity + " L is being crossed."); + return; + } + + station.add_stored_amount(value, type); + appendOutput(String.format( + "Stock changed of %s at %s by %.2f litre.", + type, getDisplayName(station), value + )); + txtAmount.setText(""); + } + } catch (NumberFormatException ex) { + showError("Please enter a valid number for the amount."); + } catch (ArithmeticException ex) { + showError("Error: " + ex.getMessage()); + } catch (NoSuchFuelTypeError ex) { + showError("This fuel station does not offer the fuel type " + type); + } + }); + + int y = 0; + gbc.gridx = 0; gbc.gridy = y; + panel.add(lblAmount, gbc); + gbc.gridx = 1; + panel.add(txtAmount, gbc); + + y++; + gbc.gridx = 0; gbc.gridy = y; gbc.gridwidth = 2; + panel.add(rbAbsolute, gbc); + + y++; + gbc.gridy = y; + panel.add(rbDelta, gbc); + + y++; + gbc.gridy = y; + panel.add(btnSave, gbc); + + return panel; + } + + private int getCapacity(FuelStation station, FuelType type) throws NoSuchFuelTypeError { + for (Fuel f : station.fuels) { + if (f.FUEL_TYPE == type) { + return f.CAPACITY; + } + } + throw new NoSuchFuelTypeError("This fuel station does not offer the fuel type " + type); + } + + /** + * Create Panel for searching for a fuel station with a specific fuel type + * + * @author Sergej Pavlenko + */ + private JPanel createSearchPanel() { + JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + + JButton btnListFuelStations = new JButton("Show fuel stations with chosen fuel type"); + btnListFuelStations.addActionListener(e -> { + FuelType type = (FuelType) comboFuelTypes.getSelectedItem(); + StringBuilder sb = new StringBuilder(); + sb.append("Fuel station with fuel type ").append(type).append(":\n"); + for (FuelStation station : Main.fuelStations) { + try { + station.getStored_amount(type); + sb.append(" - ").append(getDisplayName(station)).append("\n"); + } catch (NoSuchFuelTypeError ex) { + } + } + appendOutput(sb.toString()); + }); + + panel.add(btnListFuelStations); + return panel; + } + + /** + * Create Panel for making new fuel stations + * + * @author Sergej Pavlenko + */ + private JPanel createNewFuelStationPanel() { + JPanel panel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5, 5, 5, 5); + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.anchor = GridBagConstraints.WEST; + + JRadioButton rbSmall = new JRadioButton("Small fuel station", true); + JRadioButton rbMedium = new JRadioButton("Medium fuel station", true); + JRadioButton rbLarge = new JRadioButton("Large fuel station", true); + + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(rbSmall); + buttonGroup.add(rbMedium); + buttonGroup.add(rbLarge); + + JLabel lblAtrributes = new JLabel("Special attribute:"); + JTextField txtAtrributes = new JTextField(15); + JLabel lblHint = new JLabel("Small: amount of vending machines, Medium: m^2, Large: supermarket-company"); + + JButton btnAdd = new JButton("Add fuel station"); + btnAdd.addActionListener(e -> { + try { + if (rbSmall.isSelected()) { + short vendingMachines = Short.parseShort(txtAtrributes.getText().trim()); + Main.addNewFuelStation(vendingMachines); + appendOutput("Fuel station with " + vendingMachines + " vending machines has been added."); + } else if (rbMedium.isSelected()) { + float retailSpace = Float.parseFloat(txtAtrributes.getText().replace(",", ".").trim()); + Main.addNewFuelStation(retailSpace); + appendOutput("Fuel station with " + retailSpace + " m^2 retail space has been added."); + } else if (rbLarge.isSelected()) { + String supermarketCompany = txtAtrributes.getText().trim(); + Main.addNewFuelStation(supermarketCompany); + appendOutput("Fuel station with supermarket-company" + supermarketCompany + " has been added."); + } + refreshStationNames(); + txtAtrributes.setText(""); + } catch (NumberFormatException ex) { + showError("Please enter a valid number (for small / medium)."); + } catch (IllegalArgumentException ex) { + showError(ex.getMessage()); + } + }); + + int y = 0; + gbc.gridx = 0; gbc.gridy = y; + gbc.gridwidth = 3; + panel.add(new JLabel("Type of new fuel station:"), gbc); + + y++; + gbc.gridy = y; + gbc.gridwidth = 1; + panel.add(rbSmall, gbc); + gbc.gridx = 1; + panel.add(rbMedium, gbc); + gbc.gridx = 2; + panel.add(rbLarge, gbc); + + y++; + gbc.gridx = 0; gbc.gridy = y; + panel.add(lblAtrributes, gbc); + gbc.gridx = 1; gbc.gridwidth = 2; + panel.add(txtAtrributes, gbc); + + y++; + gbc.gridx = 0; gbc.gridy = y; + gbc.gridwidth = 3; + panel.add(lblHint, gbc); + + y++; + gbc.gridy = y; + panel.add(btnAdd, gbc); + + return panel; + } + ++ /** ++ * Create Panel for overview of fuel stations ++ * ++ * @return overview Panel ++ * ++ * @author Sergej Pavlenko ++ */ ++ private JPanel createOverviewPanel() { ++ JPanel panel = new JPanel(new BorderLayout()); ++ ++ fuelTableModel = new DefaultTableModel(new Object[]{"Fuel station", "Station type", "Fuel", "Amount (L)", "Capacity (L)", "Price (€/L)"}, 0) { ++ @Override ++ public boolean isCellEditable(int row, int column) { ++ return false; ++ } ++ }; ++ ++ tableFuelTypesPerStation = new JTable(fuelTableModel); ++ ++ JScrollPane scrollPane = new JScrollPane(tableFuelTypesPerStation); ++ ++ JButton btnRefresh = new JButton("Refresh"); ++ btnRefresh.addActionListener(e -> refreshFuelTable()); ++ ++ JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); ++ topPanel.add(new JLabel("Overview of all fuels per fuel station")); ++ topPanel.add(btnRefresh); ++ ++ panel.add(topPanel, BorderLayout.NORTH); ++ panel.add(scrollPane, BorderLayout.CENTER); ++ ++ refreshFuelTable(); ++ ++ return panel; ++ } ++ + /** + * Updates the selection of fuel stations for ComboBox and List + * + * @author Sergej Pavlenko + */ + private void refreshStationNames() { + String[] names = buildStationNames(); + + comboFuelStations.setModel(new DefaultComboBoxModel<>(names)); + + listFuelStations.setListData(names); + } + ++ /** ++ * Updates table to keep up with changes ++ * ++ * @author Sergej Pavlenko ++ */ ++ private void refreshFuelTable() { ++ if (fuelTableModel == null) { ++ return; ++ } ++ ++ fuelTableModel.setRowCount(0); ++ ++ for (FuelStation station : Main.fuelStations) { ++ String stationName = getDisplayName(station); ++ String stationType = station.getClass().getSimpleName(); ++ ++ for (Fuel fuel : station.fuels) { ++ Object[] row = new Object[] { ++ stationName, ++ stationType, ++ fuel.FUEL_TYPE, ++ fuel.getStored_amount(), ++ fuel.CAPACITY, ++ fuel.getPrice() ++ }; ++ fuelTableModel.addRow(row); ++ } ++ } ++ } ++ + private String getDisplayName(FuelStation station) { + int index = Main.fuelStations.indexOf(station); + if (index >= 0 && index < comboFuelStations.getItemCount()) { + return comboFuelStations.getItemAt(index); + } + return station.getClass().getSimpleName(); + } + ++ /** ++ * Creates a text output area ++ * ++ * @param text text output area ++ * ++ * @author Sergej Pavlenko ++ */ + private void appendOutput(String text) { + outputArea.append(text + "\n\n"); + outputArea.setCaretPosition(outputArea.getDocument().getLength()); + } + ++ /** ++ * Creates an error message ++ * ++ * @param message error message ++ * ++ * @author Sergej Pavlenko ++ */ + private void showError(String message) { + JOptionPane.showMessageDialog(this, message, "Error", JOptionPane.ERROR_MESSAGE); + } +}