Skip to content

Commit a8cdb2b

Browse files
committed
Merge branch 'develop' into feature/save_active_work_item_periodically
# Conflicts: # src/main/java/de/doubleslash/keeptime/controller/Controller.java
2 parents ba5e2df + b8b0af4 commit a8cdb2b

File tree

11 files changed

+362
-45
lines changed

11 files changed

+362
-45
lines changed

src/main/java/de/doubleslash/keeptime/Main.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import de.doubleslash.keeptime.common.FontProvider;
3434
import de.doubleslash.keeptime.common.Resources;
3535
import de.doubleslash.keeptime.common.Resources.RESOURCE;
36+
import de.doubleslash.keeptime.controller.Controller;
3637
import de.doubleslash.keeptime.model.Model;
3738
import de.doubleslash.keeptime.model.Project;
3839
import de.doubleslash.keeptime.model.Settings;
@@ -41,7 +42,6 @@
4142
import de.doubleslash.keeptime.viewpopup.GlobalScreenListener;
4243
import de.doubleslash.keeptime.viewpopup.ViewControllerPopup;
4344
import javafx.application.Application;
44-
import javafx.event.EventHandler;
4545
import javafx.fxml.FXMLLoader;
4646
import javafx.scene.Parent;
4747
import javafx.scene.Scene;
@@ -59,7 +59,6 @@
5959
import javafx.scene.paint.Color;
6060
import javafx.stage.Stage;
6161
import javafx.stage.StageStyle;
62-
import javafx.stage.WindowEvent;
6362

6463
@SpringBootApplication
6564
public class Main extends Application {
@@ -74,6 +73,8 @@ public class Main extends Application {
7473

7574
private Model model;
7675

76+
private Controller controller;
77+
7778
private ViewController viewController;
7879

7980
private GlobalScreenListener globalScreenListener;
@@ -87,6 +88,7 @@ public void init() throws Exception {
8788
springContext = SpringApplication.run(Main.class);
8889
// TODO test if everywhere is used the same model
8990
model = springContext.getBean(Model.class);
91+
controller = springContext.getBean(Controller.class);
9092
model.setSpringContext(springContext);
9193
}
9294

@@ -199,7 +201,12 @@ private void readSettings() {
199201
model.useHotkey.set(settings.isUseHotkey());
200202
model.displayProjectsRight.set(settings.isDisplayProjectsRight());
201203
model.hideProjectsOnMouseExit.set(settings.isHideProjectsOnMouseExit());
204+
model.screenSettings.proportionalX.set(settings.getWindowXProportion());
205+
model.screenSettings.proportionalY.set(settings.getWindowYProportion());
206+
model.screenSettings.screenHash.set(settings.getScreenHash());
207+
model.screenSettings.saveWindowPosition.set(settings.isSaveWindowPosition());
202208
model.remindIfNotesAreEmpty.set(settings.isRemindIfNotesAreEmpty());
209+
203210
}
204211

205212
private void initialisePopupUI(final Stage primaryStage) throws IOException {
@@ -233,13 +240,12 @@ private void initialisePopupUI(final Stage primaryStage) throws IOException {
233240

234241
private void initialiseUI(final Stage primaryStage) throws IOException {
235242
LOG.debug("Initialising main UI.");
236-
Pane mainPane;
237243

238244
// Load root layout from fxml file.
239245
final FXMLLoader loader = new FXMLLoader();
240246
loader.setLocation(Resources.getResource(RESOURCE.FXML_VIEW_LAYOUT));
241247
loader.setControllerFactory(springContext::getBean);
242-
mainPane = loader.load();
248+
final Pane mainPane = loader.load();
243249
primaryStage.initStyle(StageStyle.TRANSPARENT);
244250
// Show the scene containing the root layout.
245251
final Scene mainScene = new Scene(mainPane, Color.TRANSPARENT);
@@ -252,12 +258,8 @@ private void initialiseUI(final Stage primaryStage) throws IOException {
252258
primaryStage.setAlwaysOnTop(true);
253259
primaryStage.setResizable(false);
254260

255-
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
256-
@Override
257-
public void handle(final WindowEvent event) {
258-
LOG.info("On close request");
259-
}
260-
});
261+
primaryStage.setOnCloseRequest(windowEvent -> LOG.info("On close request"));
262+
261263
primaryStage.show();
262264
viewController = loader.getController();
263265
// Give the controller access to the main app.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package de.doubleslash.keeptime.common;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
import javafx.geometry.Rectangle2D;
7+
import javafx.stage.Screen;
8+
9+
/**
10+
* Helper to handle screen coordinates. Converts between absolute coordinates to screen+proportional coordinates. E.g.
11+
* you have two screens, each with 1000px width. Absolute position gives you 1500px and this class will get you hash for
12+
* screen #2 and proportional value 0.5. <br>
13+
* Reference #38
14+
*/
15+
public class ScreenPosHelper {
16+
17+
private static final Logger LOG = LoggerFactory.getLogger(ScreenPosHelper.class);
18+
19+
private int screenHash;
20+
21+
private double absoluteX;
22+
private double absoluteY;
23+
24+
private double proportionalX;
25+
private double proportionalY;
26+
27+
public ScreenPosHelper(final int screenhash, final double proportionalX, final double proportionalY) {
28+
this.screenHash = screenhash;
29+
this.proportionalX = proportionalX;
30+
this.proportionalY = proportionalY;
31+
calcAbsolutePosition();
32+
}
33+
34+
public ScreenPosHelper(final double absoluteX, final double absoluteY) {
35+
this.absoluteX = absoluteX;
36+
this.absoluteY = absoluteY;
37+
calcProportionalPosition();
38+
}
39+
40+
public double getAbsoluteX() {
41+
return absoluteX;
42+
}
43+
44+
public void setAbsoluteX(final double absolutX) {
45+
this.absoluteX = absolutX;
46+
calcProportionalPosition();
47+
}
48+
49+
public double getAbsoluteY() {
50+
return absoluteY;
51+
}
52+
53+
public void setAbsoluteY(final double absolutY) {
54+
this.absoluteY = absolutY;
55+
calcProportionalPosition();
56+
}
57+
58+
public int getScreenHash() {
59+
return screenHash;
60+
}
61+
62+
public double getProportionalX() {
63+
return proportionalX;
64+
}
65+
66+
public double getProportionalY() {
67+
return proportionalY;
68+
}
69+
70+
public void resetPositionIfInvalid() {
71+
if (!isPositionValid()) {
72+
final Screen screen = getScreenWithHashOrPrimary(this.screenHash);
73+
final Rectangle2D screenBounds = screen.getBounds();
74+
LOG.warn(
75+
"Position is not in the range of the screen. Screen (hash '{}') range '{}'. Calculated positions '{}'/'{}'. Setting to '0'/'0'.",
76+
screen.hashCode(), screenBounds, absoluteX, absoluteY);
77+
proportionalX = 0;
78+
proportionalY = 0;
79+
absoluteX = 0;
80+
absoluteY = 0;
81+
}
82+
}
83+
84+
private void calcProportionalPosition() {
85+
Screen screen = Screen.getPrimary();
86+
for (final Screen s : Screen.getScreens()) {
87+
if (s.getBounds().contains(this.absoluteX, this.absoluteY)) {
88+
screen = s;
89+
break;
90+
}
91+
}
92+
this.screenHash = screen.hashCode();
93+
final Rectangle2D bounds = screen.getBounds();
94+
final double xInScreen = absoluteX - bounds.getMinX();
95+
this.proportionalX = xInScreen / bounds.getWidth();
96+
final double yInScreen = absoluteY - bounds.getMinY();
97+
this.proportionalY = yInScreen / bounds.getHeight();
98+
99+
}
100+
101+
private void calcAbsolutePosition() {
102+
final Screen screen = getScreenWithHashOrPrimary(this.screenHash);
103+
final Rectangle2D screenBounds = screen.getBounds();
104+
105+
this.absoluteX = screenBounds.getMinX() + (screenBounds.getWidth() * this.proportionalX);
106+
this.absoluteY = screenBounds.getMinY() + (screenBounds.getHeight() * this.proportionalY);
107+
}
108+
109+
private boolean isPositionValid() {
110+
final Screen screen = getScreenWithHashOrPrimary(this.screenHash);
111+
final Rectangle2D screenBounds = screen.getBounds();
112+
return screenBounds.contains(this.absoluteX, this.absoluteY);
113+
}
114+
115+
private Screen getScreenWithHashOrPrimary(final int screenHash) {
116+
for (final Screen s : Screen.getScreens()) {
117+
if (s.hashCode() == screenHash) {
118+
return s;
119+
}
120+
}
121+
LOG.warn("Could not find wanted screen with hash '{}'. Using primary.", screenHash);
122+
return Screen.getPrimary();
123+
}
124+
125+
}

src/main/java/de/doubleslash/keeptime/controller/Controller.java

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import de.doubleslash.keeptime.model.Settings;
3838
import de.doubleslash.keeptime.model.Work;
3939
import javafx.collections.ObservableList;
40-
import javafx.scene.paint.Color;
4140

4241
@Service
4342
public class Controller {
@@ -119,25 +118,24 @@ public void addNewProject(final Project project) {
119118
model.getProjectRepository().saveAll(changedProjects);
120119
}
121120

122-
public void updateSettings(final Color hoverBackgroundColor, final Color hoverFontColor,
123-
final Color defaultBackgroundColor, final Color defaultFontColor, final Color taskBarColor,
124-
final boolean useHotkey, final boolean displayProjectsRight, final boolean hideProjectsOnMouseExit,
125-
final boolean emptyNoteReminder) {
126-
// TODO create holder for all the properties (or reuse Settings.class?)
127-
final Settings settings = model.getSettingsRepository().findAll().get(0);
128-
settings.setTaskBarColor(taskBarColor);
129-
130-
settings.setDefaultBackgroundColor(defaultBackgroundColor);
131-
settings.setDefaultFontColor(defaultFontColor);
132-
133-
settings.setHoverBackgroundColor(hoverBackgroundColor);
134-
settings.setHoverFontColor(hoverFontColor);
135-
settings.setUseHotkey(useHotkey);
136-
settings.setDisplayProjectsRight(displayProjectsRight);
137-
settings.setHideProjectsOnMouseExit(hideProjectsOnMouseExit);
138-
settings.setRemindIfNotesAreEmpty(emptyNoteReminder);
139-
140-
model.getSettingsRepository().save(settings);
121+
public void updateSettings(final Settings newValuedSettings) {
122+
Settings settings = model.getSettingsRepository().findAll().get(0);
123+
124+
settings.setTaskBarColor(newValuedSettings.getTaskBarColor());
125+
settings.setDefaultBackgroundColor(newValuedSettings.getDefaultBackgroundColor());
126+
settings.setDefaultFontColor(newValuedSettings.getDefaultFontColor());
127+
settings.setHoverBackgroundColor(newValuedSettings.getHoverBackgroundColor());
128+
settings.setHoverFontColor(newValuedSettings.getHoverFontColor());
129+
settings.setUseHotkey(newValuedSettings.isUseHotkey());
130+
settings.setDisplayProjectsRight(newValuedSettings.isDisplayProjectsRight());
131+
settings.setHideProjectsOnMouseExit(newValuedSettings.isHideProjectsOnMouseExit());
132+
settings.setSaveWindowPosition(newValuedSettings.isSaveWindowPosition());
133+
settings.setWindowXProportion(newValuedSettings.getWindowXProportion());
134+
settings.setWindowYProportion(newValuedSettings.getWindowYProportion());
135+
settings.setScreenHash(newValuedSettings.getScreenHash());
136+
settings.setRemindIfNotesAreEmpty(newValuedSettings.isRemindIfNotesAreEmpty());
137+
138+
settings = model.getSettingsRepository().save(settings);
141139

142140
model.defaultBackgroundColor.set(settings.getDefaultBackgroundColor());
143141
model.defaultFontColor.set(settings.getDefaultFontColor());
@@ -147,13 +145,28 @@ public void updateSettings(final Color hoverBackgroundColor, final Color hoverFo
147145
model.useHotkey.set(settings.isUseHotkey());
148146
model.displayProjectsRight.set(settings.isDisplayProjectsRight());
149147
model.hideProjectsOnMouseExit.set(settings.isHideProjectsOnMouseExit());
148+
model.screenSettings.saveWindowPosition.set(settings.isSaveWindowPosition());
149+
model.screenSettings.proportionalX.set(settings.getWindowXProportion());
150+
model.screenSettings.proportionalY.set(settings.getWindowYProportion());
151+
model.screenSettings.screenHash.set(settings.getScreenHash());
150152
model.remindIfNotesAreEmpty.set(settings.isRemindIfNotesAreEmpty());
151153
}
152154

153155
@PreDestroy
154156
public void shutdown() {
155157
LOG.info("Controller shutdown");
156-
saveCurrentWork(dateProvider.dateTimeNow());
158+
159+
LOG.info("Changing project to persist current work on shutdown.");
160+
changeProject(model.getIdleProject(), 0);
161+
162+
LOG.info("Updating settings to persist local changes on shutdown.");
163+
final Settings newSettings = new Settings(model.hoverBackgroundColor.get(), model.hoverFontColor.get(),
164+
model.defaultBackgroundColor.get(), model.defaultFontColor.get(), model.taskBarColor.get(),
165+
model.useHotkey.get(), model.displayProjectsRight.get(), model.hideProjectsOnMouseExit.get(),
166+
model.screenSettings.proportionalX.get(), model.screenSettings.proportionalY.get(),
167+
model.screenSettings.screenHash.get(), model.screenSettings.saveWindowPosition.get(),
168+
model.remindIfNotesAreEmpty.get());
169+
updateSettings(newSettings);
157170
}
158171

159172
public void deleteProject(final Project p) {
@@ -235,13 +248,13 @@ public void deleteWork(final Work workToBeDeleted) {
235248
* Changes the indexes of the originalList parameter to have a consistent order.
236249
*
237250
* @param originalList
238-
* list of all projects to adapt the indexes for
251+
* list of all projects to adapt the indexes for
239252
* @param changedProject
240-
* the project which has changed which already has the new index
253+
* the project which has changed which already has the new index
241254
* @param oldIndex
242-
* the old index of the changed project
255+
* the old index of the changed project
243256
* @param newIndex
244-
* the new index of the changed project (which the projects also already has)
257+
* the new index of the changed project (which the projects also already has)
245258
* @return all projects whose index has been adapted
246259
*/
247260
List<Project> resortProjectIndexes(final List<Project> originalList, final Project changedProject,
@@ -278,9 +291,9 @@ List<Project> resortProjectIndexes(final List<Project> originalList, final Proje
278291
* Decreases all indexes by one, after the removed index
279292
*
280293
* @param originalList
281-
* list of all projects to adapt the indexes for
294+
* list of all projects to adapt the indexes for
282295
* @param removedIndex
283-
* the index which has been removed
296+
* the index which has been removed
284297
* @return all projects whose index has been adapted
285298
*/
286299
List<Project> adaptProjectIndexesAfterRemoving(final List<Project> originalList, final int removedIndex) {

src/main/java/de/doubleslash/keeptime/model/Model.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ public Model(final ProjectRepository projectRepository, final WorkRepository wor
8282

8383
public final ObjectProperty<Boolean> remindIfNotesAreEmpty = new SimpleObjectProperty<>(false);
8484

85+
public final ScreenSettings screenSettings = new ScreenSettings();
86+
8587
private ConfigurableApplicationContext springContext;
8688

8789
public void setWorkRepository(final WorkRepository workRepository) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package de.doubleslash.keeptime.model;
2+
3+
import javafx.beans.property.ObjectProperty;
4+
import javafx.beans.property.SimpleObjectProperty;
5+
6+
public class ScreenSettings {
7+
public final ObjectProperty<Boolean> saveWindowPosition = new SimpleObjectProperty<>(false);
8+
public final ObjectProperty<Double> proportionalX = new SimpleObjectProperty<>(0.5);
9+
public final ObjectProperty<Double> proportionalY = new SimpleObjectProperty<>(0.5);
10+
public final ObjectProperty<Integer> screenHash = new SimpleObjectProperty<>(0);
11+
}

0 commit comments

Comments
 (0)