Compare commits
10 Commits
513e25b3df
...
4a91c4bbc9
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a91c4bbc9 | |||
| 2db714d353 | |||
| 23a8fc5f3e | |||
| ea5b262610 | |||
| b7078f4e5d | |||
| 0908275eba | |||
| 0a0a602a11 | |||
| b8e69b3549 | |||
| 909a29d5e3 | |||
| 668fc0f63d |
@@ -24,7 +24,7 @@ mvn package
|
||||
Using Maven:
|
||||
|
||||
```bash
|
||||
mvn exec:java@com.calendar.CalendarApp
|
||||
mvn exec:java
|
||||
```
|
||||
|
||||
Using Java directly:
|
||||
|
||||
@@ -10,12 +10,14 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class CalendarPanel extends JPanel {
|
||||
private PointEngine pointEngine;
|
||||
private YearMonth currentMonth;
|
||||
private final int cellHeight = 60;
|
||||
private final int cellWidth = 80;
|
||||
private final Set<LocalDate> selectedDates = new HashSet<>();
|
||||
|
||||
public CalendarPanel() {
|
||||
public CalendarPanel(PointEngine pointEngine) {
|
||||
this.pointEngine = pointEngine;
|
||||
this.currentMonth = YearMonth.now();
|
||||
setPreferredSize(new Dimension(7 * cellWidth, 8 * cellHeight));
|
||||
setBackground(Color.WHITE);
|
||||
@@ -77,7 +79,13 @@ public class CalendarPanel extends JPanel {
|
||||
}
|
||||
|
||||
public double getTotalPoints() {
|
||||
return selectedDates.size() * 1.0;
|
||||
double totalPoints = 0.0;
|
||||
|
||||
for (LocalDate date : selectedDates) {
|
||||
totalPoints += pointEngine.getPointsOfDay(date);
|
||||
}
|
||||
|
||||
return totalPoints;
|
||||
}
|
||||
|
||||
private LocalDate getDateAtPoint(int x, int y) {
|
||||
@@ -149,12 +157,13 @@ public class CalendarPanel extends JPanel {
|
||||
boolean isToday = cellDate.equals(today);
|
||||
boolean isSelected = selectedDates.contains(cellDate);
|
||||
|
||||
if (isSelected) {
|
||||
if (isSelected && isToday) {
|
||||
g.setColor(new Color(123, 166, 180));
|
||||
g.fillRect(x, y, cellWidth, cellHeight);
|
||||
} else if (isSelected) {
|
||||
g.setColor(new Color(173, 216, 230));
|
||||
g.fillRect(x, y, cellWidth, cellHeight);
|
||||
}
|
||||
|
||||
if (isToday) {
|
||||
} else if (isToday) {
|
||||
g.setColor(new Color(255, 200, 100));
|
||||
g.fillRect(x, y, cellWidth, cellHeight);
|
||||
}
|
||||
@@ -167,7 +176,7 @@ public class CalendarPanel extends JPanel {
|
||||
int textY = y + (cellHeight - fm.getHeight()) / 2 + fm.getAscent() - 8;
|
||||
g.drawString(dayStr, textX, textY);
|
||||
|
||||
String pointsStr = "(1.0)";
|
||||
String pointsStr = "(" + pointEngine.getPointsOfDay(cellDate) + ")";
|
||||
Font smallFont = new Font("Arial", Font.PLAIN, 10);
|
||||
FontMetrics smallFm = g.getFontMetrics(smallFont);
|
||||
g.setFont(smallFont);
|
||||
|
||||
108
src/main/java/net/themusicinnoise/vaccalc/PointEngine.java
Normal file
108
src/main/java/net/themusicinnoise/vaccalc/PointEngine.java
Normal file
@@ -0,0 +1,108 @@
|
||||
package net.themusicinnoise.vaccalc;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PointEngine {
|
||||
private double defaultPoints;
|
||||
|
||||
static private class PointRule {
|
||||
private enum RuleType {
|
||||
DAY_OF_WEEK,
|
||||
MONTH,
|
||||
DATE,
|
||||
}
|
||||
|
||||
static final Pattern DOW_PATTERN = Pattern.compile("dow=(sun|mon|tue|wed|thu|fri|sat) (\\d+\\.\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
static final Pattern MONTH_PATTERN = Pattern.compile("m=(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) (\\d+\\.\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2}) (\\d+\\.\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private RuleType type;
|
||||
private DayOfWeek dow;
|
||||
private Month mon;
|
||||
private LocalDate date;
|
||||
private double points;
|
||||
|
||||
public PointRule(String def) {
|
||||
Matcher dowMatcher = DOW_PATTERN.matcher(def);
|
||||
Matcher monthMatcher = MONTH_PATTERN.matcher(def);
|
||||
Matcher dateMatcher = DATE_PATTERN.matcher(def);
|
||||
|
||||
if (dowMatcher.find()) {
|
||||
this.type = RuleType.DAY_OF_WEEK;
|
||||
this.points = Double.parseDouble(dowMatcher.group(2));
|
||||
this.dow = DayOfWeek.from(DateTimeFormatter.ofPattern("EEE").parse(dowMatcher.group(1)));
|
||||
} else if (monthMatcher.find()) {
|
||||
this.type = RuleType.MONTH;
|
||||
this.points = Double.parseDouble(monthMatcher.group(2));
|
||||
this.mon = Month.from(DateTimeFormatter.ofPattern("MMM").parse(monthMatcher.group(1)));
|
||||
} else if (dateMatcher.find()) {
|
||||
this.type = RuleType.DATE;
|
||||
this.points = Double.parseDouble(dateMatcher.group(2));
|
||||
this.date = LocalDate.parse(dateMatcher.group(1), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid line: '" + def + "'");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean applies(LocalDate date) {
|
||||
switch (type) {
|
||||
case DAY_OF_WEEK:
|
||||
return this.dow == date.getDayOfWeek();
|
||||
case MONTH:
|
||||
return this.mon == date.getMonth();
|
||||
case DATE:
|
||||
return this.date.isEqual(date);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public double getPoints() { return points; }
|
||||
}
|
||||
private List<PointRule> rules;
|
||||
|
||||
public PointEngine() {
|
||||
defaultPoints = 1.0;
|
||||
rules = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void importPointsFile(File pointsFile) {
|
||||
Pattern defaultPattern = Pattern.compile("default (\\d+\\.\\d+)");
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(pointsFile))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
Matcher defaultMatcher = defaultPattern.matcher(line);
|
||||
if (defaultMatcher.find()) {
|
||||
defaultPoints = Double.parseDouble(defaultMatcher.group(1));
|
||||
} else {
|
||||
rules.add(new PointRule(line));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to read points file: " + pointsFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() { rules.clear(); }
|
||||
|
||||
public double getPointsOfDay(LocalDate date) {
|
||||
double points = defaultPoints;
|
||||
for (PointRule rule : rules) {
|
||||
if (rule.applies(date)) {
|
||||
points = rule.getPoints();
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,14 @@ package net.themusicinnoise.vaccalc;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.time.YearMonth;
|
||||
|
||||
public class VacCalc extends JFrame {
|
||||
private CalendarPanel calendarPanel;
|
||||
private JLabel monthLabel;
|
||||
private JLabel pointsLabel;
|
||||
private PointEngine pointEngine;
|
||||
|
||||
public VacCalc() {
|
||||
setTitle("VacCalc");
|
||||
@@ -15,7 +17,41 @@ public class VacCalc extends JFrame {
|
||||
setResizable(false);
|
||||
setLocationRelativeTo(null);
|
||||
|
||||
calendarPanel = new CalendarPanel();
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
JMenu appMenu = new JMenu("VacCalc");
|
||||
JMenuItem importItem = new JMenuItem("Import points");
|
||||
importItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent ev) {
|
||||
JFileChooser fileChooser = new JFileChooser();
|
||||
int ret = fileChooser.showOpenDialog(VacCalc.this);
|
||||
if(ret == JFileChooser.APPROVE_OPTION) {
|
||||
try {
|
||||
pointEngine.importPointsFile(fileChooser.getSelectedFile());
|
||||
} catch(RuntimeException ex) {
|
||||
ex.printStackTrace();
|
||||
JOptionPane.showMessageDialog(VacCalc.this, ex.getMessage(), "Parsing Error",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
pointEngine.reset();
|
||||
}
|
||||
}
|
||||
calendarPanel.repaint();
|
||||
}
|
||||
});
|
||||
appMenu.add(importItem);
|
||||
JMenuItem exitItem = new JMenuItem("Exit");
|
||||
exitItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
appMenu.add(exitItem);
|
||||
menuBar.add(appMenu);
|
||||
setJMenuBar(menuBar);
|
||||
|
||||
pointEngine = new PointEngine();
|
||||
calendarPanel = new CalendarPanel(pointEngine);
|
||||
|
||||
JPanel headerPanel = createHeaderPanel();
|
||||
JPanel footerPanel = createFooterPanel();
|
||||
@@ -87,14 +123,14 @@ public class VacCalc extends JFrame {
|
||||
|
||||
private void updateMonthLabel() {
|
||||
YearMonth current = calendarPanel.getCurrentMonth();
|
||||
monthLabel.setText(String.format("%s %d",
|
||||
current.getMonth().toString(),
|
||||
monthLabel.setText(String.format("%s %d",
|
||||
current.getMonth().toString(),
|
||||
current.getYear()));
|
||||
}
|
||||
|
||||
private void updatePointsLabel() {
|
||||
double points = calendarPanel.getTotalPoints();
|
||||
pointsLabel.setText(String.format("Total Points: %.1f", points));
|
||||
pointsLabel.setText(String.format("Total Points: %.3f", points));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
6
vac-points.txt
Normal file
6
vac-points.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
default 1.0
|
||||
dow=Fri 0.825
|
||||
2026-12-24 0.5
|
||||
2026-12-31 0.5
|
||||
m=Jul 0.825
|
||||
m=Aug 0.825
|
||||
Reference in New Issue
Block a user