Added several improvements, changes and bug fixes

This commit is contained in:
Robert Vokac 2024-03-16 14:51:11 +00:00
parent 8787ba9551
commit 30d4ff30a4
No known key found for this signature in database
GPG Key ID: 693D30BEE3329055
15 changed files with 457 additions and 228 deletions

View File

@ -8,6 +8,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
/** /**
* @author Robert Vokac * @author Robert Vokac
@ -31,7 +32,7 @@ public class Activity implements Comparable<Activity> {
private int spentHours; private int spentHours;
private int spentMinutes; private int spentMinutes;
private String flags; private String flags;
private String nextActivityId; private int sortkey;
public String createSubject() { public String createSubject() {
return ticket + SUBJECT_FIELD_SEPARATOR + name; return ticket + SUBJECT_FIELD_SEPARATOR + name;
@ -39,13 +40,18 @@ public class Activity implements Comparable<Activity> {
public String createTotalComment() { public String createTotalComment() {
return ticket + SUBJECT_FIELD_SEPARATOR + year + "-" + month + "-" + day return ticket + SUBJECT_FIELD_SEPARATOR + year + "-" + month + "-" + day
+ SUBJECT_FIELD_SEPARATOR + ((spentHours + spentMinutes / 60d) + SUBJECT_FIELD_SEPARATOR + (
+ "h") + SUBJECT_FIELD_SEPARATOR NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(spentHours + spentMinutes / 60d)
+ "h") + SUBJECT_FIELD_SEPARATOR
+ comment; + comment;
} }
public Set<String> flagsAsSet() { public Set<String> flagsAsSet() {
Set<String> set = new HashSet<>(); Set<String> set = new HashSet<>();
for(String flag:flags.split(":")) { for(String flag:flags.split(":")) {
if(flag.isEmpty()) {
//nothing to do
continue;
}
set.add(flag); set.add(flag);
} }
return set; return set;
@ -64,24 +70,10 @@ public class Activity implements Comparable<Activity> {
@Override @Override
public int compareTo(Activity o) { public int compareTo(Activity o) {
int result = Integer.valueOf(year).compareTo(Integer.valueOf(o.year)); return Integer.valueOf(sortkey).compareTo(Integer.valueOf(o.sortkey));
if(result != 0) { }
return result;
} public String getSpentTimeAsString() {
result = Integer.valueOf(month).compareTo(Integer.valueOf(o.month)); return (getSpentHours() < 10 ? "0" : "") + getSpentHours() + ":" + (getSpentMinutes() < 10 ? "0" : "") + getSpentMinutes();
if(result != 0) {
return result;
}
result = Integer.valueOf(day).compareTo(Integer.valueOf(o.day));
if(result != 0) {
return result;
}
if(this.nextActivityId != null && this.nextActivityId.equals(o.getId())) {
return -1;
}
if(o.nextActivityId != null && o.nextActivityId.equals(o.getId())) {
return 1;
}
return 0;
} }
} }

View File

@ -17,14 +17,14 @@ public class ActivityForStats extends Activity {
public ActivityForStats(String id, int year, int month, int day, public ActivityForStats(String id, int year, int month, int day,
String name, String name,
String comment, String ticket, int spentHours, int spentMinutes, String comment, String ticket, int spentHours, int spentMinutes,
String flags, String nextActivityId, String flags, int sortkey,
int todaySpentHours, int todaySpentHours,
int todaySpentMinutes, int todaySpentMinutes,
int todayRemainsHours, int todayRemainsHours,
int todayRemainsMinutes) { int todayRemainsMinutes) {
super(id, year, month, day, name, comment, ticket, spentHours, super(id, year, month, day, name, comment, ticket, spentHours,
spentMinutes, spentMinutes,
flags, nextActivityId); flags, sortkey);
this.todaySpentHours = todaySpentHours; this.todaySpentHours = todaySpentHours;
this.todaySpentMinutes = todaySpentMinutes; this.todaySpentMinutes = todaySpentMinutes;
this.todayRemainsHours = todayRemainsHours; this.todayRemainsHours = todayRemainsHours;

View File

@ -12,10 +12,6 @@ public interface ActivityRepositoryApi {
void create(Activity activity); void create(Activity activity);
Activity getLastActivityForDay(int year, int month, int day);
Activity getPreviousActivity(String id);
List<Activity> list(int year, int month, int day); List<Activity> list(int year, int month, int day);
List<Activity> list(String ticket); List<Activity> list(String ticket);
@ -28,4 +24,10 @@ public interface ActivityRepositoryApi {
public List<String> getYears(); public List<String> getYears();
public void putToClipboard(Activity activity);
public Activity getFromClipboard();
public int getLargestSortkey(int year, int month, int day);
} }

View File

@ -1,17 +1,18 @@
package org.nanoboot.utils.timecalc.persistence.impl.sqlite; package org.nanoboot.utils.timecalc.persistence.impl.sqlite;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.entity.Activity;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import java.util.ArrayList; import java.util.ArrayList;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import java.util.List; import java.util.List;
import org.nanoboot.utils.timecalc.app.TimeCalcException; import java.util.OptionalInt;
import org.nanoboot.utils.timecalc.entity.Activity;
import org.nanoboot.utils.timecalc.utils.common.Utils;
/** /**
* @author Robert Vokac * @author Robert Vokac
@ -25,9 +26,10 @@ public class ActivityRepositorySQLiteImpl implements ActivityRepositoryApi {
this.sqliteConnectionFactory = sqliteConnectionFactory; this.sqliteConnectionFactory = sqliteConnectionFactory;
} }
private Activity activityInClipboard = null;
@Override @Override
public void create(Activity activity) { public void create(Activity activity) {
Activity lastActivityForDay = getLastActivityForDay(activity.getYear(), activity.getMonth(), activity.getDay());
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb sb
.append("INSERT INTO ") .append("INSERT INTO ")
@ -51,7 +53,7 @@ public class ActivityRepositorySQLiteImpl implements ActivityRepositoryApi {
stmt.setInt(++i, activity.getSpentHours()); stmt.setInt(++i, activity.getSpentHours());
stmt.setInt(++i, activity.getSpentMinutes()); stmt.setInt(++i, activity.getSpentMinutes());
stmt.setString(++i, activity.getFlags()); stmt.setString(++i, activity.getFlags());
stmt.setNull(++i, Types.VARCHAR); stmt.setInt(++i, activity.getSortkey());
// //
stmt.execute(); stmt.execute();
@ -64,11 +66,6 @@ public class ActivityRepositorySQLiteImpl implements ActivityRepositoryApi {
throw new TimeCalcException(ex); throw new TimeCalcException(ex);
} }
if(lastActivityForDay != null) {
lastActivityForDay.setNextActivityId(activity.getId());
update(lastActivityForDay);
}
} }
@Override @Override
@ -103,12 +100,7 @@ public class ActivityRepositorySQLiteImpl implements ActivityRepositoryApi {
ex.printStackTrace(); ex.printStackTrace();
throw new TimeCalcException(ex); throw new TimeCalcException(ex);
} }
Activity previousActivity = getPreviousActivity(id);
Activity nextActivity = read(activityToBeDeleted.getNextActivityId());
if(previousActivity != null) {
previousActivity.setNextActivityId(nextActivity == null ? null : nextActivity.getId());
update(previousActivity);
}
} }
@ -210,7 +202,7 @@ public class ActivityRepositorySQLiteImpl implements ActivityRepositoryApi {
.append(ActivityTable.SPENT_HOURS).append("=?, ") .append(ActivityTable.SPENT_HOURS).append("=?, ")
.append(ActivityTable.SPENT_MINUTES).append("=?, ") .append(ActivityTable.SPENT_MINUTES).append("=?, ")
.append(ActivityTable.FLAGS).append("=?, ") .append(ActivityTable.FLAGS).append("=?, ")
.append(ActivityTable.NEXT_ACTIVITY_ID).append("=? ") .append(ActivityTable.SORTKEY).append("=? ")
.append(" WHERE ").append( .append(" WHERE ").append(
ActivityTable.ID).append("=?"); ActivityTable.ID).append("=?");
@ -225,7 +217,7 @@ public class ActivityRepositorySQLiteImpl implements ActivityRepositoryApi {
stmt.setInt(++i, activity.getSpentHours()); stmt.setInt(++i, activity.getSpentHours());
stmt.setInt(++i, activity.getSpentMinutes()); stmt.setInt(++i, activity.getSpentMinutes());
stmt.setString(++i, activity.getFlags()); stmt.setString(++i, activity.getFlags());
stmt.setString(++i, activity.getNextActivityId()); stmt.setInt(++i, activity.getSortkey());
stmt.setString(++i, activity.getId()); stmt.setString(++i, activity.getId());
@ -293,7 +285,7 @@ public class ActivityRepositorySQLiteImpl implements ActivityRepositoryApi {
rs.getInt(ActivityTable.SPENT_HOURS), rs.getInt(ActivityTable.SPENT_HOURS),
rs.getInt(ActivityTable.SPENT_MINUTES), rs.getInt(ActivityTable.SPENT_MINUTES),
rs.getString(ActivityTable.FLAGS), rs.getString(ActivityTable.FLAGS),
rs.getString(ActivityTable.NEXT_ACTIVITY_ID) rs.getInt(ActivityTable.SORTKEY)
); );
} }
@ -336,101 +328,37 @@ public class ActivityRepositorySQLiteImpl implements ActivityRepositoryApi {
return result; return result;
} }
@Override @Override
public Activity getLastActivityForDay(int year, int month, int day) { public void putToClipboard(Activity activity) {
this.activityInClipboard = activity;
List<Activity> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb
.append("SELECT * FROM ")
.append(ActivityTable.TABLE_NAME)
.append(" WHERE ")
.append(ActivityTable.YEAR).append("=? AND ")
.append(ActivityTable.MONTH).append("=? AND ")
.append(ActivityTable.DAY).append("=? AND ")
.append(ActivityTable.NEXT_ACTIVITY_ID)
.append(" IS NULL ");
String sql = sb.toString();
int i = 0;
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
stmt.setInt(++i, year);
stmt.setInt(++i, month);
stmt.setInt(++i, day);
rs = stmt.executeQuery();
while (rs.next()) {
result.add(extractActivityFromResultSet(rs));
}
} catch (SQLException | ClassNotFoundException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
if(result.isEmpty()) {
return null;
}
if(result.size() == 1) {
return result.get(0);
}
throw new TimeCalcException("Fatal error: More (" + result.size() + ") than one activity per one day with next activity id set to null: " + year + ", " + month + ", " + day);
} }
@Override @Override
public Activity getPreviousActivity(String id) { public Activity getFromClipboard() {
if(this.activityInClipboard == null) {
List<Activity> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb
.append("SELECT * FROM ")
.append(ActivityTable.TABLE_NAME)
.append(" WHERE ")
.append(ActivityTable.NEXT_ACTIVITY_ID).append("=? ");
String sql = sb.toString();
int i = 0;
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
stmt.setString(++i, id);
rs = stmt.executeQuery();
while (rs.next()) {
result.add(extractActivityFromResultSet(rs));
}
} catch (SQLException | ClassNotFoundException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
if(result.isEmpty()) {
return null; return null;
} }
if(result.size() == 1) { Activity a = new Activity(
result.get(0); null,
2000, 1,1,
activityInClipboard.getName(),
activityInClipboard.getComment(),
activityInClipboard.getTicket(),
0,0, "", 1);
return activityInClipboard;
}
@Override
public int getLargestSortkey(int year, int month, int day) {
OptionalInt optional =
list(year, month, day).stream().map(Activity::getSortkey)
.mapToInt(e -> e).max();
if (optional.isPresent()) {
System.out.println("getLargestSortkey=" +optional.getAsInt());
return optional.getAsInt();
} else {
return 1;
} }
throw new TimeCalcException("Fatal error: More than one activity, which is previous for this activity id:" + id);
} }
} }

View File

@ -37,7 +37,7 @@ class ActivityTable {
public static final String SPENT_HOURS = "SPENT_HOURS"; public static final String SPENT_HOURS = "SPENT_HOURS";
public static final String SPENT_MINUTES = "SPENT_MINUTES"; public static final String SPENT_MINUTES = "SPENT_MINUTES";
public static final String FLAGS = "FLAGS"; public static final String FLAGS = "FLAGS";
public static final String NEXT_ACTIVITY_ID = "NEXT_ACTIVITY_ID"; public static final String SORTKEY = "SORTKEY";
private ActivityTable() { private ActivityTable() {
//Not meant to be instantiated. //Not meant to be instantiated.

View File

@ -5,6 +5,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane; import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
@ -41,7 +42,6 @@ public class ActivitiesWindow extends TWindow {
List<String> yearsList = activityRepository.getYears(); List<String> yearsList = activityRepository.getYears();
TTabbedPane tp = new TTabbedPane(); TTabbedPane tp = new TTabbedPane();
JButton addYearButton = new JButton("Add year"); JButton addYearButton = new JButton("Add year");
addYearButton.setBounds(SwingUtils.MARGIN, SwingUtils.MARGIN, 150, 30); addYearButton.setBounds(SwingUtils.MARGIN, SwingUtils.MARGIN, 150, 30);
add(addYearButton); add(addYearButton);

View File

@ -1,17 +1,11 @@
package org.nanoboot.utils.timecalc.swing.common; package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.entity.Activity;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.FlowLayout; import java.awt.FlowLayout;
import java.awt.Font; import java.awt.Font;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/** /**
* @author Robert * @author Robert
@ -19,6 +13,14 @@ import java.awt.event.MouseListener;
*/ */
public class ActivityHeader extends JPanel { public class ActivityHeader extends JPanel {
private static final Font FONT = new Font("sans", Font.BOLD, 12); private static final Font FONT = new Font("sans", Font.BOLD, 12);
public static final Dimension PREFERRED_SIZE = new Dimension(200, 40);
public static final Dimension PREFERRED_SIZE1 = new Dimension(80, 40);
public static final Dimension PREFERRED_SIZE3 = new Dimension(60, 40);
public static final Dimension PREFERRED_SIZE4 = new Dimension(40, 40);
public static final Dimension PREFERRED_SIZE2 = new Dimension(100, 40);
private TTextField sortkey = new TTextField("Sortkey");
private TTextField name = new TTextField("Name"); private TTextField name = new TTextField("Name");
private TTextField comment = new TTextField("Comment"); private TTextField comment = new TTextField("Comment");
private TTextField ticket = new TTextField("Ticket"); private TTextField ticket = new TTextField("Ticket");
@ -27,12 +29,13 @@ public class ActivityHeader extends JPanel {
private TTextField flags = new TTextField("Flags"); private TTextField flags = new TTextField("Flags");
private TTextField subject = new TTextField("Subject"); private TTextField subject = new TTextField("Subject");
private TTextField totalComment = new TTextField("Total comment"); private TTextField totalComment = new TTextField("Total comment");
private TTextField today = new TTextField("Today"); private TTextField done = new TTextField("Done");
private TTextField remains = new TTextField("Remains"); private TTextField todo = new TTextField("Todo");
public ActivityHeader() { public ActivityHeader() {
this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
add(sortkey);
add(name); add(name);
add(comment); add(comment);
add(ticket); add(ticket);
@ -41,20 +44,22 @@ public class ActivityHeader extends JPanel {
add(flags); add(flags);
add(subject); add(subject);
add(totalComment); add(totalComment);
add(today); add(done);
add(remains); add(todo);
name.setPreferredSize(new Dimension(200, 40)); sortkey.setPreferredSize(PREFERRED_SIZE1);
comment.setPreferredSize(new Dimension(200, 40)); name.setPreferredSize(PREFERRED_SIZE);
ticket.setPreferredSize(new Dimension(80, 40)); comment.setPreferredSize(PREFERRED_SIZE);
spentTime.setPreferredSize(new Dimension(80, 40)); ticket.setPreferredSize(PREFERRED_SIZE1);
spentTime.setPreferredSize(PREFERRED_SIZE1);
flags.setPreferredSize(new Dimension(100, 40)); flags.setPreferredSize(PREFERRED_SIZE2);
subject.setPreferredSize(new Dimension(100, 40)); subject.setPreferredSize(PREFERRED_SIZE2);
totalComment.setPreferredSize(new Dimension(100, 40)); totalComment.setPreferredSize(PREFERRED_SIZE2);
today.setPreferredSize(new Dimension(80, 40)); done.setPreferredSize(PREFERRED_SIZE3);
remains.setPreferredSize(new Dimension(80, 40)); todo.setPreferredSize(PREFERRED_SIZE3);
sortkey.setEditable(false);
name.setEditable(false); name.setEditable(false);
comment.setEditable(false); comment.setEditable(false);
ticket.setEditable(false); ticket.setEditable(false);
@ -63,9 +68,10 @@ public class ActivityHeader extends JPanel {
flags.setEditable(false); flags.setEditable(false);
subject.setEditable(false); subject.setEditable(false);
totalComment.setEditable(false); totalComment.setEditable(false);
today.setEditable(false); done.setEditable(false);
remains.setEditable(false); todo.setEditable(false);
sortkey.setFont(FONT);
name.setFont(FONT); name.setFont(FONT);
comment.setFont(FONT); comment.setFont(FONT);
ticket.setFont(FONT); ticket.setFont(FONT);
@ -74,9 +80,10 @@ public class ActivityHeader extends JPanel {
flags.setFont(FONT); flags.setFont(FONT);
subject.setFont(FONT); subject.setFont(FONT);
totalComment.setFont(FONT); totalComment.setFont(FONT);
today.setFont(FONT); done.setFont(FONT);
remains.setFont(FONT); todo.setFont(FONT);
sortkey.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
name.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); name.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
comment.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); comment.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
ticket.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); ticket.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
@ -85,8 +92,8 @@ public class ActivityHeader extends JPanel {
flags.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); flags.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
subject.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); subject.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
totalComment.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); totalComment.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
today.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); done.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
remains.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); todo.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
//this.setBorder(BorderFactory.createLineBorder(Color.ORANGE, 1)); //this.setBorder(BorderFactory.createLineBorder(Color.ORANGE, 1));
setAlignmentX(LEFT_ALIGNMENT); setAlignmentX(LEFT_ALIGNMENT);

View File

@ -1,25 +1,37 @@
package org.nanoboot.utils.timecalc.swing.common; package org.nanoboot.utils.timecalc.swing.common;
import lombok.Getter;
import org.nanoboot.utils.timecalc.entity.Activity; import org.nanoboot.utils.timecalc.entity.Activity;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi; import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import org.nanoboot.utils.timecalc.utils.common.TTime;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.FlowLayout; import java.awt.FlowLayout;
import java.awt.event.MouseEvent; import java.awt.Toolkit;
import java.awt.event.MouseListener; import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
/** /**
* @author Robert * @author Robert
* @since 13.03.2024 * @since 13.03.2024
*/ */
public class ActivityPanel extends JPanel { public class ActivityPanel extends JPanel implements Comparable<ActivityPanel> {
public static final Dimension PREFERRED_SIZE = new Dimension(200, 40);
public static final Dimension PREFERRED_SIZE1 = new Dimension(80, 40);
public static final Dimension PREFERRED_SIZE3 = new Dimension(60, 40);
public static final Dimension PREFERRED_SIZE4 = new Dimension(40, 40);
public static final Dimension PREFERRED_SIZE2 = new Dimension(100, 40);
private final ActivityRepositoryApi activityRepository; private final ActivityRepositoryApi activityRepository;
@Getter
private final Activity activity; private final Activity activity;
private TTextField sortkey = new TTextField("1");
private TTextField name = new TTextField(""); private TTextField name = new TTextField("");
private TTextField comment = new TTextField(""); private TTextField comment = new TTextField("");
private TTextField ticket = new TTextField(""); private TTextField ticket = new TTextField("");
@ -28,14 +40,17 @@ public class ActivityPanel extends JPanel {
private TTextField flags = new TTextField("Flags"); private TTextField flags = new TTextField("Flags");
private TTextField subject = new TTextField(""); private TTextField subject = new TTextField("");
private TTextField totalComment = new TTextField(""); private TTextField totalComment = new TTextField("");
private TTextField today = new TTextField("00:00"); public TTextField today = new TTextField("00:00");
private TTextField remains = new TTextField("00:00"); public TTextField remains = new TTextField("00:00");
@Getter
private boolean deleted;
public ActivityPanel(ActivityRepositoryApi activityRepository, public ActivityPanel(ActivityRepositoryApi activityRepository,
Activity activity) { Activity activity, DayPanel dayPanel) {
this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
this.activity = activity; this.activity = activity;
add(sortkey);
add(name); add(name);
add(comment); add(comment);
add(ticket); add(ticket);
@ -47,19 +62,46 @@ public class ActivityPanel extends JPanel {
add(today); add(today);
add(remains); add(remains);
name.setPreferredSize(new Dimension(200, 40)); // JButton moveThisButton = new SmallTButton("Move ");
comment.setPreferredSize(new Dimension(200, 40)); // JButton moveBeforeButton = new SmallTButton("Here");
ticket.setPreferredSize(new Dimension(80, 40)); JButton copyButton = new SmallTButton("Copy");
spentTime.setPreferredSize(new Dimension(80, 40)); JButton deleteButton = new SmallTButton("Delete");
JButton subjectButton = new SmallTButton("Sub");
JButton totalCommentButton = new SmallTButton("TotCom");
// add(moveThisButton);
// add(moveBeforeButton);
add(copyButton);
add(deleteButton);
add(subjectButton);
add(totalCommentButton);
// moveThisButton.setFont(SwingUtils.SMALL_FONT);
// moveBeforeButton.setFont(SwingUtils.SMALL_FONT);
copyButton.setFont(SwingUtils.SMALL_FONT);
deleteButton.setFont(SwingUtils.SMALL_FONT);
subjectButton.setFont(SwingUtils.SMALL_FONT);
totalCommentButton.setFont(SwingUtils.SMALL_FONT);
flags.setPreferredSize(new Dimension(100, 40)); sortkey.setPreferredSize(PREFERRED_SIZE1);
subject.setPreferredSize(new Dimension(100, 40)); name.setPreferredSize(PREFERRED_SIZE);
totalComment.setPreferredSize(new Dimension(100, 40)); comment.setPreferredSize(PREFERRED_SIZE);
today.setPreferredSize(new Dimension(80, 40)); ticket.setPreferredSize(PREFERRED_SIZE1);
remains.setPreferredSize(new Dimension(80, 40)); spentTime.setPreferredSize(PREFERRED_SIZE1);
flags.setPreferredSize(PREFERRED_SIZE2);
subject.setPreferredSize(PREFERRED_SIZE2);
totalComment.setPreferredSize(PREFERRED_SIZE2);
today.setPreferredSize(PREFERRED_SIZE3);
remains.setPreferredSize(PREFERRED_SIZE3);
// moveThisButton.setPreferredSize(PREFERRED_SIZE4);
// moveBeforeButton.setPreferredSize(PREFERRED_SIZE4);
copyButton.setPreferredSize(PREFERRED_SIZE4);
deleteButton.setPreferredSize(PREFERRED_SIZE4);
subjectButton.setPreferredSize(PREFERRED_SIZE4);
totalCommentButton.setPreferredSize(PREFERRED_SIZE3);
this.setPreferredSize(new Dimension(getWidth(), 40)); this.setPreferredSize(new Dimension(getWidth(), 40));
sortkey.setEditable(false);
name.setEditable(false); name.setEditable(false);
comment.setEditable(false); comment.setEditable(false);
ticket.setEditable(false); ticket.setEditable(false);
@ -71,6 +113,7 @@ public class ActivityPanel extends JPanel {
today.setEditable(false); today.setEditable(false);
remains.setEditable(false); remains.setEditable(false);
sortkey.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
name.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); name.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
comment.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); comment.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
ticket.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); ticket.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
@ -82,55 +125,153 @@ public class ActivityPanel extends JPanel {
today.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); today.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
remains.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); remains.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
name.addMouseListener(new MouseListener() { sortkey.addMouseListener((MouseClickedListener) e -> {
@Override String result = (String) JOptionPane.showInputDialog(
public void mouseClicked(MouseEvent e) { null,
String result = (String) JOptionPane.showInputDialog( "Select new sortkey",
null, "New sortkey",
"Select new name", JOptionPane.PLAIN_MESSAGE,
"New name", null,
JOptionPane.PLAIN_MESSAGE, null,
null, sortkey.getText()
null, );
name.getText() if (result != null) {
); activity.setSortkey(Integer.valueOf(result));
if (result != null) { activityRepository.update(activity);
activity.setName(result); sortkey.setText(result);
activityRepository.update(activity); dayPanel.sortActivityPanels();
name.setText(result);
}
} }
});
@Override name.addMouseListener((MouseClickedListener) e -> {
public void mousePressed(MouseEvent e) { String result = (String) JOptionPane.showInputDialog(
null,
"Select new name",
"New name",
JOptionPane.PLAIN_MESSAGE,
null,
null,
name.getText()
);
if (result != null) {
activity.setName(result);
activityRepository.update(activity);
name.setText(result);
subject.setText(activity.createSubject());
} }
});
@Override comment.addMouseListener((MouseClickedListener) e -> {
public void mouseReleased(MouseEvent e) { String result = (String) JOptionPane.showInputDialog(
null,
"Select new comment",
"New comment",
JOptionPane.PLAIN_MESSAGE,
null,
null,
comment.getText()
);
if (result != null) {
activity.setComment(result);
activityRepository.update(activity);
comment.setText(result);
totalComment.setText(activity.createTotalComment());
} }
});
@Override ticket.addMouseListener((MouseClickedListener) e -> {
public void mouseEntered(MouseEvent e) { String result = (String) JOptionPane.showInputDialog(
null,
"Select new ticket",
"New ticket",
JOptionPane.PLAIN_MESSAGE,
null,
null,
ticket.getText()
);
if (result != null) {
activity.setTicket(result);
activityRepository.update(activity);
ticket.setText(result);
subject.setText(activity.createSubject());
totalComment.setText(activity.createTotalComment());
} }
});
spentTime.addMouseListener((MouseClickedListener) e -> {
String result = (String) JOptionPane.showInputDialog(
null,
"Select new spent time",
"New spent time",
JOptionPane.PLAIN_MESSAGE,
null,
null,
spentTime.getText()
);
if (result != null) {
TTime spentTimeTTime = new TTime(result);
activity.setSpentHours(spentTimeTTime.getHour());
activity.setSpentMinutes(spentTimeTTime.getMinute());
activityRepository.update(activity);
spentTime.setText(result);
totalComment.setText(activity.createTotalComment());
dayPanel.sortActivityPanels();
}
});
@Override flags.addMouseListener((MouseClickedListener) e -> {
public void mouseExited(MouseEvent e) { String result = (String) JOptionPane.showInputDialog(
null,
"Select new flags",
"New flags",
JOptionPane.PLAIN_MESSAGE,
null,
null,
flags.getText()
);
if (result != null) {
activity.setFlags(result);
activityRepository.update(activity);
flags.setText(result);
} }
}); });
name.setText(activity.getName()); name.setText(activity.getName());
comment.setText(activity.getComment()); comment.setText(activity.getComment());
ticket.setText(activity.getTicket()); ticket.setText(activity.getTicket());
spentTime.setText((activity.getSpentHours() < 10 ? "0" : "") + activity spentTime.setText(activity.getSpentTimeAsString());
.getSpentHours() + ":" + (activity.getSpentMinutes() < 10 ? "0" :
"") + activity.getSpentMinutes());
flags.setText(activity.getFlags()); flags.setText(activity.getFlags());
subject.setText(activity.createSubject());
totalComment.setText(activity.createTotalComment());
sortkey.setText(String.valueOf(activity.getSortkey()));
this.activityRepository = activityRepository; this.activityRepository = activityRepository;
//this.setBorder(BorderFactory.createLineBorder(Color.ORANGE, 1)); //this.setBorder(BorderFactory.createLineBorder(Color.ORANGE, 1));
setAlignmentX(LEFT_ALIGNMENT); setAlignmentX(LEFT_ALIGNMENT);
// moveThisButton.addActionListener(e-> {
// //dayPanel.switchPositionsForThisActivityAndThePreviousActivity(getActivity());
// //dayPanel.markActivityAsToBeMoved(getActivity());
// });
//
// moveBeforeButton.addActionListener(e-> {
// //dayPanel.moveMarkedActivityBeforeThisActivity(getActivity());
// });
deleteButton.addActionListener(e -> {
activityRepository.delete(this.activity.getId());
deleted = true;
});
copyButton.addActionListener(e -> {
activityRepository.putToClipboard(this.activity);
});
subjectButton.addActionListener(e-> {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(subject.getText()), null);
});
totalCommentButton.addActionListener(e-> {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(totalComment.getText()), null);
});
dayPanel.sortActivityPanels();
}
@Override
public int compareTo(ActivityPanel o) {
return this.getActivity().compareTo(o.getActivity());
} }
} }

View File

@ -2,15 +2,30 @@ package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.entity.Activity; import org.nanoboot.utils.timecalc.entity.Activity;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi; import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.common.TTime;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;
import java.awt.Component;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.FlowLayout; import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* @author robertvokac * @author robertvokac
@ -24,6 +39,8 @@ public class DayPanel extends JPanel {
private final Map<String, DayPanel> map = new HashMap<>(); private final Map<String, DayPanel> map = new HashMap<>();
private final ActivityRepositoryApi activityRepository; private final ActivityRepositoryApi activityRepository;
private JButton loadButton; private JButton loadButton;
private JScrollPane scrollPane;
private JPanel panelInsideScrollPane;
public DayPanel(String yearIn, String monthIn, String dayIn, public DayPanel(String yearIn, String monthIn, String dayIn,
ActivityRepositoryApi activityRepository) { ActivityRepositoryApi activityRepository) {
@ -33,7 +50,7 @@ public class DayPanel extends JPanel {
this.month = monthIn; this.month = monthIn;
this.day = dayIn; this.day = dayIn;
this.activityRepository = activityRepository; this.activityRepository = activityRepository;
setSize(1350, 600); setSize(1450, 600);
this.setLayout(null); this.setLayout(null);
this.loadButton = new JButton("Load"); this.loadButton = new JButton("Load");
@ -67,12 +84,25 @@ public class DayPanel extends JPanel {
buttons.setAlignmentX(LEFT_ALIGNMENT); buttons.setAlignmentX(LEFT_ALIGNMENT);
JButton newButton = new JButton("New"); JButton newButton = new JButton("New");
JButton pasteButton = new JButton("Paste"); JButton pasteButton = new JButton("Paste");
JButton reviewButton = new JButton("Review");;
buttons.add(newButton); buttons.add(newButton);
buttons.add(pasteButton); buttons.add(pasteButton);
buttons.add(reviewButton);
add(buttons); add(buttons);
this.scrollPane
= new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
add(scrollPane);
this.panelInsideScrollPane = new JPanel();
panelInsideScrollPane.setLayout(new BoxLayout(panelInsideScrollPane, BoxLayout.Y_AXIS));
scrollPane.setViewportView(panelInsideScrollPane);
ActivityHeader activityHeader = new ActivityHeader(); ActivityHeader activityHeader = new ActivityHeader();
add(activityHeader); panelInsideScrollPane.add(activityHeader);
activityHeader.setMaximumSize(new Dimension(1200, 40)); activityHeader.setMaximumSize(new Dimension(1200, 40));
buttons.setMaximumSize(new Dimension(1000, 40)); buttons.setMaximumSize(new Dimension(1000, 40));
for (Activity a : activityRepository.list( for (Activity a : activityRepository.list(
Integer.valueOf(year), Integer.valueOf(year),
@ -80,26 +110,118 @@ public class DayPanel extends JPanel {
Integer.valueOf(day))) { Integer.valueOf(day))) {
ActivityPanel comp = ActivityPanel comp =
new ActivityPanel(activityRepository, a); new ActivityPanel(activityRepository, a, this);
comp.setMaximumSize(new Dimension(1200, 40)); comp.setMaximumSize(new Dimension(1300, 40));
add(comp); panelInsideScrollPane.add(comp);
} }
new Timer(100, e -> {
List<Component>
list = Arrays.stream(panelInsideScrollPane.getComponents()).filter(c-> c instanceof ActivityPanel).filter(c-> ((ActivityPanel)c).isDeleted()).collect(
Collectors.toList());
if(!list.isEmpty()) {
list.forEach(c->panelInsideScrollPane.remove(c));
}
revalidate();
}).start();
revalidate(); revalidate();
newButton.addActionListener(e-> { newButton.addActionListener(e-> {
Activity newActivity = new Activity(UUID.randomUUID().toString(), Integer.valueOf(year), Integer.valueOf(month), Integer.valueOf(day), "", "", "", 0, 0, "", null); Activity newActivity = new Activity(UUID.randomUUID().toString(), Integer.valueOf(year), Integer.valueOf(month), Integer.valueOf(day), "", "", "", 0, 0, "", 1 + activityRepository.getLargestSortkey(Integer.valueOf(year), Integer.valueOf(month), Integer.valueOf(day)));
ActivityPanel comp = ActivityPanel comp =
new ActivityPanel(activityRepository, newActivity); new ActivityPanel(activityRepository, newActivity, this);
comp.setMaximumSize(new Dimension(1200, 40)); comp.setMaximumSize(new Dimension(1200, 40));
add(comp); add(comp);
activityRepository.create(newActivity); activityRepository.create(newActivity);
panelInsideScrollPane.add(comp);
revalidate(); revalidate();
}); });
// for (int i = 0; i < 10; i++) { pasteButton.addActionListener(e-> {
// add(new ActivityPanel(activityRepository, Activity afc = activityRepository.getFromClipboard();
// new Activity("id", 2000, 7, 7, "name", "comment", "ticket", 2, 30, if(afc == null) {
// "a b c", null))); Utils.showNotification("There is no activity in clipboard. Nothing to do.");
// } return;
}
Activity newActivity = new Activity(UUID.randomUUID().toString(), Integer.valueOf(year), Integer.valueOf(month), Integer.valueOf(day),
afc.getName(), afc.getComment(), afc.getTicket(), 0, 0, "", 1 + activityRepository.getLargestSortkey(Integer.valueOf(year), Integer.valueOf(month), Integer.valueOf(day)));
ActivityPanel comp =
new ActivityPanel(activityRepository, newActivity, this);
comp.setMaximumSize(new Dimension(1200, 40));
add(comp);
activityRepository.create(newActivity);
panelInsideScrollPane.add(comp);
revalidate();
});
reviewButton.addActionListener(e->{
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(Arrays
.stream(panelInsideScrollPane.getComponents())
.filter(c-> c instanceof ActivityPanel)
.map(ap->((ActivityPanel) ap).getActivity())
.map(a->a.createTotalComment())
.collect(
Collectors.joining("\n"))), null);
});
// for (int i = 0; i < 10; i++) {
// add(new ActivityPanel(activityRepository,
// new Activity("id", 2000, 7, 7, "name", "comment", "ticket", 2, 30,
// "a b c", null)));
// }
}
public List<Activity> getActivities() {
return Arrays
.stream(panelInsideScrollPane.getComponents())
.filter(c-> c instanceof ActivityPanel)
.map(ap->((ActivityPanel) ap).getActivity()).collect(Collectors.toList());
}
public int getIndexForActivityPanel(Activity a) {
for(int i = 0;i<panelInsideScrollPane.getComponentCount();i++) {
Component c = panelInsideScrollPane.getComponent(i);
if(c instanceof ActivityPanel) {
if(((ActivityPanel)c).getActivity().equals(a)) {
return i;
}
}
}
return -1;
}
public ActivityPanel getActivityPanelForActivity(Activity a) {
Optional<Component> optional = Arrays
.stream(panelInsideScrollPane.getComponents())
.filter(c-> c instanceof ActivityPanel)
.filter(c-> ((ActivityPanel) c).getActivity().equals(a))
.findFirst();
if(optional.isPresent()) {
return (ActivityPanel) optional.get();
} else {
return null;
}
}
public void sortActivityPanels() {
List<ActivityPanel> list = new ArrayList<>();
Arrays
.stream(panelInsideScrollPane.getComponents())
.filter(c-> c instanceof ActivityPanel).forEach(e-> list.add((ActivityPanel) e));
Collections.sort(list);
for(ActivityPanel ap:list) {
panelInsideScrollPane.remove(ap);
}
double done = 0d;
double todo = 8d;
for(ActivityPanel ap:list) {
panelInsideScrollPane.add(ap);
double now = ap.getActivity().getSpentHours() + ap.getActivity().getSpentMinutes() / 60d;
done = done + now;
todo = todo - now;
ap.today.setText(TTime.ofMilliseconds((int)(done * 60d * 60d * 1000d)).toString().substring(0,5));
ap.remains.setText(TTime.ofMilliseconds((int)(todo * 60d * 60d * 1000d)).toString().substring(0,5));
}
revalidate();
} }
} }

View File

@ -32,7 +32,7 @@ public class MonthPanel extends JPanel {
setLayout(null); setLayout(null);
this.tp = new TTabbedPane(); this.tp = new TTabbedPane();
add(tp); add(tp);
tp.setBounds(0, 0, 1350, 650); tp.setBounds(0, 0, 1450, 650);
ChangeListener changeListener = new ChangeListener() { ChangeListener changeListener = new ChangeListener() {
private boolean secondOrLaterChange = false; private boolean secondOrLaterChange = false;

View File

@ -0,0 +1,31 @@
package org.nanoboot.utils.timecalc.swing.common;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* @author Robert
* @since 14.03.2024
*/
public interface MouseClickedListener extends MouseListener {
@Override
default void mousePressed(MouseEvent e) {
}
@Override
default void mouseReleased(MouseEvent e) {
}
@Override
default void mouseEntered(MouseEvent e) {
}
@Override
default void mouseExited(MouseEvent e) {
}
}

View File

@ -10,9 +10,13 @@ public class SmallTButton extends TButton {
private static final Insets INSETS = new Insets(1, 1, 1, 1); private static final Insets INSETS = new Insets(1, 1, 1, 1);
public SmallTButton(char character) { public SmallTButton(String s) {
super(String.valueOf(character), 15, 15); super(s, 15, 15);
//setFont(SwingUtils.SMALL_FONT); //setFont(SwingUtils.SMALL_FONT);
setMargin(INSETS); setMargin(INSETS);
} }
public SmallTButton(char character) {
this(String.valueOf(character));
}
} }

View File

@ -26,7 +26,7 @@ public class YearPanel extends JPanel {
setLayout(null); setLayout(null);
this.tp = new TTabbedPane(); this.tp = new TTabbedPane();
add(tp); add(tp);
tp.setBounds(0, 0, 1350, 700); tp.setBounds(0, 0, 1450, 700);
ChangeListener changeListener = new ChangeListener() { ChangeListener changeListener = new ChangeListener() {
private boolean secondOrLaterChange = false; private boolean secondOrLaterChange = false;

View File

@ -0,0 +1 @@
ALTER TABLE "ACTIVITY" DROP COLUMN "NEXT_ACTIVITY_ID";

View File

@ -0,0 +1 @@
ALTER TABLE "ACTIVITY" ADD COLUMN "SORTKEY" NUMBER DEFAULT 1;