ActivitiesWindow - wip

This commit is contained in:
Robert Vokac 2024-03-10 15:39:23 +00:00
parent 73e5ba2ceb
commit d340250f3e
No known key found for this signature in database
GPG Key ID: 693D30BEE3329055
14 changed files with 603 additions and 32 deletions

44
.gitignore vendored
View File

@ -1,22 +1,22 @@
### IntelliJ IDEA ###
.idea
logs/*
*.iws
*.iml
*.ipr
target/
starttime.txt
overtime.txt
highlighted
proxy.txt
out.txt
pocasi.txt
test.txt
timecalc*.conf
focus.txt
dist/*
time-calc-current-profile.txt
time-calc-profiles.txt
.tc/*
time-calc-jokes.txt
### IntelliJ IDEA ###
.idea
logs/*
*.iws
*.iml
*.ipr
target/
starttime.txt
overtime.txt
highlighted
proxy.txt
out.txt
pocasi.txt
test.txt
timecalc*.conf
focus.txt
dist/*
time-calc-current-profile.txt
time-calc-profiles.txt
**.tc/*
time-calc-jokes.txt

View File

@ -1,5 +1,8 @@
package org.nanoboot.utils.timecalc.entity;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@ -19,13 +22,12 @@ public class Activity {
private int year;
private int month;
private int day;
private int name;
private int comment;
private int ticket;
private String name;
private String comment;
private String ticket;
private int spentHours;
private int spentMinutes;
private boolean jira;
private boolean bugzilla;
private String flags;
public String createSubject() {
return ticket + SUBJECT_FIELD_SEPARATOR + name;
@ -37,5 +39,23 @@ public class Activity {
+ "h") + SUBJECT_FIELD_SEPARATOR
+ comment;
}
public Set<String> flagsAsSet() {
Set<String> set = new HashSet<>();
for(String flag:flags.split(":")) {
set.add(flag);
}
return set;
}
public void addFlag(String flag) {
Set<String> set = flagsAsSet();
set.add(flag);
this.flags = set.stream().collect(Collectors.joining(":"));
}
public void removeFlag(String flag) {
Set<String> set = flagsAsSet();
set.remove(flag);
this.flags = set.stream().collect(Collectors.joining(":"));
}
}

View File

@ -18,5 +18,9 @@ public interface ActivityRepositoryApi {
void update(Activity activity);
WorkingDay read(String id);
void delete(String id);
public List<String> getYears();
}

View File

@ -0,0 +1,253 @@
package org.nanoboot.utils.timecalc.persistence.impl.sqlite;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import org.nanoboot.utils.timecalc.entity.WorkingDay;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import java.util.List;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.entity.Activity;
/**
* @author Robert Vokac
* @since 23.02.2024
*/
public class ActivityRepositorySQLiteImpl implements ActivityRepositoryApi {
private final SqliteConnectionFactory sqliteConnectionFactory;
public ActivityRepositorySQLiteImpl(SqliteConnectionFactory sqliteConnectionFactory) {
this.sqliteConnectionFactory = sqliteConnectionFactory;
}
@Override
public void create(Activity activity) {
StringBuilder sb = new StringBuilder();
sb
.append("INSERT INTO ")
.append(ActivityTable.TABLE_NAME)
.append(" VALUES (?,?,?,?, ?,?,?,?,?)");
String sql = sb.toString();
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
stmt.setString(++i, activity.getId());
stmt.setInt(++i, activity.getYear());
stmt.setInt(++i, activity.getMonth());
stmt.setInt(++i, activity.getDay());
//
stmt.setString(++i, activity.getName());
stmt.setString(++i, activity.getComment());
stmt.setString(++i, activity.getTicket());
stmt.setInt(++i, activity.getSpentHours());
stmt.setInt(++i, activity.getSpentMinutes());
stmt.setString(++i, activity.getFlags());
//
stmt.execute();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
throw new TimeCalcException(ex);
}
}
@Override
public void update(Activity activity) {
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
}
@Override
public WorkingDay read(String id) {
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
}
@Override
public void delete(String id) {
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
}
//
// @Override
// public List<WorkingDay> list(int year, int month, int day) {
//
// List<WorkingDay> result = new ArrayList<>();
// StringBuilder sb = new StringBuilder();
// sb
// .append("SELECT * FROM ")
// .append(WorkingDayTable.TABLE_NAME)
// .append(" WHERE ")
// .append(WorkingDayTable.YEAR).append("=? AND ")
// .append(WorkingDayTable.MONTH).append("=? ");
// if (day != 0) {
// sb.append(" AND ").append(WorkingDayTable.DAY).append("=? ");
// }
//
// String sql = sb.toString();
// int i = 0;
// ResultSet rs = null;
// try (
// Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
//
// //System.err.println(stmt.toString());
// stmt.setInt(++i, year);
// stmt.setInt(++i, month);
// if (day != 0) {
// stmt.setInt(++i, day);
// }
// rs = stmt.executeQuery();
//
// while (rs.next()) {
// result.add(extractWorkingDayFromResultSet(rs));
// }
// } catch (SQLException e) {
// System.out.println(e.getMessage());
// throw new RuntimeException(e);
// } catch (ClassNotFoundException ex) {
// System.out.println(ex.getMessage());
// throw new RuntimeException(ex);
// } finally {
// try {
// if (rs != null) {
// rs.close();
// }
// } catch (SQLException ex) {
// System.out.println(ex.getMessage());
// throw new RuntimeException(ex);
// }
// }
// return result;
////
// }
//
// @Override
// public void update(WorkingDay workingDay) {
// if(list(workingDay.getYear(), workingDay.getMonth(),workingDay.getDay()).isEmpty()) {
// create(workingDay);
// return;
// }
// System.out.println("Going to update: " + workingDay.toString());
//
// StringBuilder sb = new StringBuilder();
// sb
// .append("UPDATE ")
// .append(WorkingDayTable.TABLE_NAME)
// .append(" SET ")
// .append(WorkingDayTable.ARRIVAL_HOUR).append("=?, ")
// .append(WorkingDayTable.ARRIVAL_MINUTE).append("=?, ")
// .append(WorkingDayTable.OVERTIME_HOUR).append("=?, ")
// .append(WorkingDayTable.OVERTIME_MINUTE).append("=?, ")
// .append(WorkingDayTable.WORKING_TIME_IN_MINUTES).append("=?, ")
// .append(WorkingDayTable.PAUSE_TIME_IN_MINUTES).append("=?, ")
// .append(WorkingDayTable.NOTE).append("=? ")
// .append(" WHERE ").append(
// WorkingDayTable.ID).append("=?");
//
// String sql = sb.toString();
// //System.err.println(sql);
// try (
// Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
// int i = 0;
// stmt.setInt(++i, workingDay.getArrivalHour());
// stmt.setInt(++i, workingDay.getArrivalMinute());
// stmt.setInt(++i, workingDay.getOvertimeHour());
// stmt.setInt(++i, workingDay.getOvertimeMinute());
// stmt.setInt(++i, workingDay.getWorkingTimeInMinutes());
// stmt.setInt(++i, workingDay.getPauseTimeInMinutes());
// stmt.setString(++i, workingDay.getNote());
//
// stmt.setString(++i, workingDay.getId());
//
// int numberOfUpdatedRows = stmt.executeUpdate();
// //System.out.println("numberOfUpdatedRows=" + numberOfUpdatedRows);
// } catch (SQLException e) {
// System.out.println(e.getMessage());
// throw new RuntimeException(e);
// } catch (ClassNotFoundException ex) {
// ex.printStackTrace();
// throw new TimeCalcException(ex);
// }
// }
//
// @Override
// public WorkingDay read(int year, int month, int day) {
// List<WorkingDay> list = list(year, month, day);
// return list.isEmpty() ? null : list.get(0);
// }
//
// private WorkingDay extractWorkingDayFromResultSet(final ResultSet rs) throws SQLException {
// return new WorkingDay(
// rs.getString(WorkingDayTable.ID),
// rs.getInt(WorkingDayTable.YEAR),
// rs.getInt(WorkingDayTable.MONTH),
// rs.getInt(WorkingDayTable.DAY),
// rs.getInt(WorkingDayTable.ARRIVAL_HOUR),
// rs.getInt(WorkingDayTable.ARRIVAL_MINUTE),
// rs.getInt(WorkingDayTable.OVERTIME_HOUR),
// rs.getInt(WorkingDayTable.OVERTIME_MINUTE),
// rs.getInt(WorkingDayTable.WORKING_TIME_IN_MINUTES),
// rs.getInt(WorkingDayTable.PAUSE_TIME_IN_MINUTES),
// rs.getString(WorkingDayTable.NOTE)
// );
// }
//
@Override
public List<String> getYears() {
List<String> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb
.append("SELECT distinct ").append(WorkingDayTable.YEAR). append(" FROM ")
.append(ActivityTable.TABLE_NAME);
String sql = sb.toString();
int i = 0;
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
rs = stmt.executeQuery();
while (rs.next()) {
result.add(rs.getString(WorkingDayTable.YEAR));
}
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
return result;
}
@Override
public List<Activity> list(int year, int month, int day) {
throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
}
}

View File

@ -0,0 +1,45 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.utils.timecalc.persistence.impl.sqlite;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
class ActivityTable {
public static final String TABLE_NAME = "ACTIVITY";
public static final String ID = "ID";
public static final String YEAR = "YEAR";
public static final String MONTH = "MONTH";
public static final String DAY = "DAY";
public static final String NAME = "NAME";
public static final String COMMENT = "COMMENT";
public static final String TICKET = "TICKET";
public static final String SPENT_HOURS = "SPENT_HOURS";
public static final String SPENT_MINUTES = "SPENT_MINUTES";
public static final String FLAGS = "FLAGS";
private ActivityTable() {
//Not meant to be instantiated.
}
}

View File

@ -1,13 +1,93 @@
package org.nanoboot.utils.timecalc.swing.common;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import org.nanoboot.utils.timecalc.swing.progress.Time;
/**
* @author Robert Vokac
* @since 16.02.2024
*/
public class ActivitiesWindow extends TWindow {
public ActivitiesWindow() {
setSize(800, 600);
private final ActivityRepositoryApi activityRepository;
private final Map<String, YearPanel> years;
public ActivitiesWindow(ActivityRepositoryApi activityRepositoryApiIn, Time time) {
setSize(1200, 800);
setTitle("Activities");
this.activityRepository = activityRepositoryApiIn;
this.years = new HashMap<>();
int currentYear = time.yearProperty.getValue();
int currentMonth = time.monthProperty.getValue();
int currentDay = time.dayProperty.getValue();
String currentYearS = String.valueOf(currentYear);
String currentMonthS = String.valueOf(currentMonth);
String currentDayS = String.valueOf(currentDay);
this.setLayout(null);
ActivitiesWindow activitiesWindow = this;
List<String> yearsList = activityRepository.getYears();
TTabbedPane tp = new TTabbedPane();
JButton addYearButton = new JButton("Add year");
addYearButton.setBounds(SwingUtils.MARGIN, SwingUtils.MARGIN, 150, 30);
add(addYearButton);
JButton exitButton = new JButton("Exit");
exitButton.setBounds(SwingUtils.MARGIN + addYearButton.getWidth() + SwingUtils.MARGIN, addYearButton.getY(), 150, 30);
add(exitButton);
exitButton.addActionListener(e -> activitiesWindow.setVisible(false));
tp.setBounds(addYearButton.getX(), addYearButton.getY() + addYearButton.getHeight() + SwingUtils.MARGIN, 1180, 600);
yearsList.forEach(y -> {
final YearPanel yearPanel = new YearPanel(y);
tp.add(y, yearPanel);
years.put(y, yearPanel);
}
);
if (!yearsList.contains(currentYearS)) {
YearPanel yearPanel = new YearPanel(currentYearS);
tp.add(currentYearS, yearPanel);
years.put(currentYearS, yearPanel);
}
addYearButton.addActionListener(e -> {
String year_ = JOptionPane.showInputDialog(null,
"Please enter year.");
try {
Integer.parseInt(year_);
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(this, "Error: this is not year: " + currentYear);
throw ex;
}
for (int i = 0; i < tp.getTabCount(); i++) {
if (tp.getTitleAt(i).equals(year_)) {
String msg = "Error: this year already exists.: " + currentYear;
JOptionPane.showMessageDialog(this, msg);
throw new TimeCalcException(msg);
}
}
YearPanel yearPanel = new YearPanel(year_);
tp.add(year_, yearPanel);
years.put(currentYearS, yearPanel);
});
add(tp);
getYearPanel(currentYearS).setSelectedMonth(currentMonthS);
getYearPanel(currentYearS).getMonthPanel(currentMonthS).setSelectedDay(currentDayS);
}
public YearPanel getYearPanel(String year) {
return years.get(year);
}
}

View File

@ -0,0 +1,28 @@
package org.nanoboot.utils.timecalc.swing.common;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JPanel;
/**
*
* @author robertvokac
*/
public class DayPanel extends JPanel {
private final String year;
private final String month;
private final String day;
private final Map<String, DayPanel> map = new HashMap<>();
public DayPanel(String yearIn, String monthIn, String dayIn) {
super();
this.year = yearIn;
this.month = monthIn;
this.day = dayIn;
setSize(1050, 600);
}
}

View File

@ -36,6 +36,8 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.util.Calendar;
import org.nanoboot.utils.timecalc.entity.WorkingDay;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import org.nanoboot.utils.timecalc.persistence.impl.sqlite.ActivityRepositorySQLiteImpl;
import org.nanoboot.utils.timecalc.persistence.impl.sqlite.WorkingDayRepositorySQLiteImpl;
/**
@ -77,6 +79,8 @@ public class MainWindow extends TWindow {
private WorkingDaysWindow workingDaysWindow = null;
private boolean stopBeforeEnd = false;
private final WorkingDayRepositorySQLiteImpl workingDayRepository;
private final ActivityRepositoryApi activityRepository;
{
this.arrivalTextField = new TTextField("", 40);
@ -370,6 +374,7 @@ public class MainWindow extends TWindow {
add(remainingTextField);
add(saveButton);
this.workingDayRepository = new WorkingDayRepositorySQLiteImpl(timeCalcApp.getSqliteConnectionFactory());
this.activityRepository = new ActivityRepositorySQLiteImpl(timeCalcApp.getSqliteConnectionFactory());
//
configButton.setBoundsFromTop(departureTextFieldLabel);
@ -429,7 +434,7 @@ public class MainWindow extends TWindow {
});
activitiesButton.addActionListener(e -> {
if (activitiesWindow == null) {
this.activitiesWindow = new ActivitiesWindow();
this.activitiesWindow = new ActivitiesWindow(this.activityRepository, time);
}
activitiesWindow.setVisible(true);
});

View File

@ -0,0 +1,53 @@
package org.nanoboot.utils.timecalc.swing.common;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
/**
*
* @author robertvokac
*/
public class MonthPanel extends JPanel {
private final String year;
private final String month;
private final Map<String, DayPanel> days;
private final TTabbedPane tp;
public MonthPanel(String yearIn, String monthIn) {
super();
this.year = yearIn;
this.month = monthIn;
this.days = new HashMap<>();
setLayout(null);
this.tp = new TTabbedPane();
add(tp);
tp.setBounds(0, 0, 1100, 650);
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, Integer.valueOf(year));
cal.set(Calendar.MONTH, Integer.valueOf(month) - 1);
cal.set(Calendar.DAY_OF_MONTH, 1);
int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
for (int day = 1; day <= maxDay; day++) {
String dayS = String.valueOf(day);
DayPanel dayPanel = new DayPanel(year, month, dayS);
tp.add(dayS, dayPanel);
days.put(dayS, dayPanel);
}
}
public void setSelectedDay(String day) {
tp.switchTo(day);
}
public DayPanel getDayPanel(String day) {
return days.get(day);
}
}

View File

@ -0,0 +1,28 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package org.nanoboot.utils.timecalc.swing.common;
import javax.swing.JTabbedPane;
/**
*
* @author robertvokac
*/
public class TTabbedPane extends JTabbedPane {
public int getIndexFor(String title) {
for (int i = 0; i < getTabCount(); i++) {
if (getTitleAt(i).equals(title)) {
return i;
}
}
return -1;
}
public void switchTo(String title) {
this.setSelectedIndex(getIndexFor(title));
}
}

View File

@ -11,7 +11,6 @@ import javax.swing.JComboBox;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import org.nanoboot.utils.timecalc.entity.WorkingDay;
import org.nanoboot.utils.timecalc.entity.WorkingDayForStats;
import org.nanoboot.utils.timecalc.persistence.api.WorkingDayRepositoryApi;
@ -311,4 +310,4 @@ public class WorkingDaysWindow extends TWindow {
arrivalChart.setBounds(bounds);
add(arrivalChart);
}
}
}

View File

@ -0,0 +1,41 @@
package org.nanoboot.utils.timecalc.swing.common;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JPanel;
/**
*
* @author robertvokac
*/
public class YearPanel extends JPanel {
private final String year;
private final Map<String, MonthPanel> months;
private final TTabbedPane tp;
public YearPanel(String yearIn) {
super();
this.year = yearIn;
this.months = new HashMap<>();
setLayout(null);
this.tp = new TTabbedPane();
add(tp);
tp.setBounds(0, 0, 1150, 700);
for (int month = 1; month <= 12; month++) {
final String monthS = String.valueOf(month);
MonthPanel monthPanel = new MonthPanel(year, String.valueOf(month));
tp.add(String.valueOf(month), monthPanel);
months.put(monthS, monthPanel);
}
}
public void setSelectedMonth(String month) {
tp.switchTo(month);
}
public MonthPanel getMonthPanel(String month) {
return months.get(month);
}
}

View File

@ -0,0 +1,15 @@
CREATE TABLE "ACTIVITY" (
"ID" TEXT,
"YEAR" NUMBER NOT NULL,
"MONTH" NUMBER NOT NULL,
"DAY" NUMBER NOT NULL,
--
"NAME" TEXT NOT NULL,
"COMMENT" TEXT NOT NULL,
"TICKET" TEXT NOT NULL,
"SPENT_HOURS" NUMBER NOT NULL,
"SPENT_MINUTES" NUMBER NOT NULL,
"FLAGS" TEXT NOT NULL,
PRIMARY KEY("ID")
);