Skip to content

Commit 2757bb0

Browse files
committed
Separate pattern-related classes from component classes
1 parent 54ba90f commit 2757bb0

19 files changed

Lines changed: 507 additions & 328 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ Each component exposes a log prefix that uniquely identifies its instance. This
371371
Each template in the framework provides base classes and interfaces for creating three types of components, which
372372
form a hierarchy of inheritance and composition:
373373

374-
* **Base Component** — the fundamental implementation of the selected architectural pattern. This is the simplest and
374+
* **Component** — the fundamental implementation of the selected architectural pattern. This is the simplest and
375375
“purest” component type, providing only minimal functionality: lifecycle management and interaction between the core
376376
elements of the pattern. Base components do not support parent–child relationships and therefore cannot participate
377377
in a tree-like composition. They are intended for isolated, self-contained windows or dialogs.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2024-2025 Pavel Castornii.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.techsenger.patternfx.mvp;
18+
19+
/**
20+
*
21+
* @author Pavel Castornii
22+
*/
23+
public abstract class AbstractComponentFxView<T extends ComponentPresenter<?>> extends AbstractComponentView<T>
24+
implements ComponentFxView<T> {
25+
26+
@Override
27+
public Descriptor getDescriptor() {
28+
return getPresenter().getDescriptor();
29+
}
30+
31+
@Override
32+
protected void initialize() {
33+
build();
34+
bind();
35+
addListeners();
36+
addHandlers();
37+
}
38+
39+
@Override
40+
protected void deinitialize() {
41+
removeHandlers();
42+
removeListeners();
43+
unbind();
44+
unbuild();
45+
}
46+
47+
/**
48+
* Builds the view.
49+
*/
50+
protected void build() { }
51+
52+
/**
53+
* Makes all bindings.
54+
*/
55+
protected void bind() { }
56+
57+
/**
58+
* Initializes listeners to different properties etc.
59+
*/
60+
protected void addListeners() { }
61+
62+
/**
63+
* Initializes handlers for mouse, keyboard etc events.
64+
*/
65+
protected void addHandlers() { }
66+
67+
/**
68+
* Removes handlers.
69+
*
70+
*/
71+
protected void removeHandlers() { }
72+
73+
/**
74+
* Removes listeners.
75+
*
76+
*/
77+
protected void removeListeners() { }
78+
79+
/**
80+
* Unbinds existing bindings.
81+
*
82+
*/
83+
protected void unbind() { }
84+
85+
/**
86+
* Unbuilds the view.
87+
*/
88+
protected void unbuild() { }
89+
}

patternfx-mvp/src/main/java/com/techsenger/patternfx/mvp/AbstractHistory.java renamed to patternfx-mvp/src/main/java/com/techsenger/patternfx/mvp/AbstractComponentHistory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*
2323
* @author Pavel Castornii
2424
*/
25-
public abstract class AbstractHistory implements ComponentHistory {
25+
public abstract class AbstractComponentHistory implements ComponentHistory {
2626

2727
private boolean isNew = true;
2828

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
/*
2+
* Copyright 2024-2025 Pavel Castornii.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.techsenger.patternfx.mvp;
18+
19+
import com.techsenger.annotations.Nullable;
20+
import com.techsenger.patternfx.core.ComponentState;
21+
import com.techsenger.patternfx.core.HistoryPolicy;
22+
import static com.techsenger.patternfx.core.HistoryPolicy.ALL;
23+
import static com.techsenger.patternfx.core.HistoryPolicy.APPEARANCE;
24+
import static com.techsenger.patternfx.core.HistoryPolicy.DATA;
25+
import static com.techsenger.patternfx.core.HistoryPolicy.NONE;
26+
import com.techsenger.patternfx.core.HistoryProvider;
27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
29+
30+
/**
31+
*
32+
* @author Pavel Castornii
33+
*/
34+
public abstract class AbstractComponentPresenter<V extends View> extends AbstractPresenter<V>
35+
implements ComponentPresenter<V> {
36+
37+
private static final Logger logger = LoggerFactory.getLogger(AbstractComponentPresenter.class);
38+
39+
private final Descriptor descriptor;
40+
41+
private HistoryPolicy historyPolicy = HistoryPolicy.NONE;
42+
43+
private @Nullable HistoryProvider<? extends AbstractComponentHistory> historyProvider;
44+
45+
private @Nullable AbstractComponentHistory history;
46+
47+
public AbstractComponentPresenter(V view) {
48+
super(view);
49+
this.descriptor = createDescriptor();
50+
}
51+
52+
@Override
53+
public final void initialize() {
54+
try {
55+
if (descriptor.getState() != ComponentState.CREATING) {
56+
throw new IllegalStateException("Unexpected state of the component - " + descriptor.getState().name());
57+
}
58+
// pre-initialization
59+
preInitialize();
60+
// initialization
61+
descriptor.setState(ComponentState.INITIALIZING);
62+
if (getView() instanceof AbstractView<?>) {
63+
((AbstractComponentView<?>) getView()).initialize();
64+
}
65+
if (this.history != null) {
66+
restoreHistory();
67+
}
68+
descriptor.setState(ComponentState.INITIALIZED);
69+
logger.debug("{} Initialized the component", getDescriptor().getLogPrefix());
70+
// post-initialization
71+
postInitialize();
72+
} catch (Exception ex) {
73+
logger.error("{} Error initializing", getDescriptor().getLogPrefix(), ex);
74+
}
75+
}
76+
77+
@Override
78+
public final void deinitialize() {
79+
try {
80+
var descriptor = getDescriptor();
81+
if (descriptor.getState() != ComponentState.INITIALIZED) {
82+
throw new IllegalStateException("Unexpected state of the component - " + descriptor.getState().name());
83+
}
84+
// pre-deinitialization
85+
preDeinitialize();
86+
// deinitialization
87+
descriptor.setState(ComponentState.DEINITIALIZING);
88+
if (this.history != null) {
89+
saveHistory();
90+
}
91+
if (getView() instanceof AbstractView<?>) {
92+
((AbstractComponentView<?>) getView()).deinitialize();
93+
}
94+
descriptor.setState(ComponentState.DEINITIALIZED);
95+
logger.debug("{} Deinitialized the component", getDescriptor().getLogPrefix());
96+
// post-deinitialization
97+
postDeinitialize();
98+
} catch (Exception ex) {
99+
logger.error("{} Error deinitializing", getDescriptor().getLogPrefix(), ex);
100+
}
101+
}
102+
103+
@Override
104+
public Descriptor getDescriptor() {
105+
return descriptor;
106+
}
107+
108+
@Override
109+
public HistoryPolicy getHistoryPolicy() {
110+
return historyPolicy;
111+
}
112+
113+
@Override
114+
public void setHistoryPolicy(HistoryPolicy policy) {
115+
this.historyPolicy = policy;
116+
}
117+
118+
/**
119+
* The first method called in initialization.
120+
*/
121+
protected void preInitialize() {
122+
prepareHistory();
123+
}
124+
125+
/**
126+
* The last method called in initialization.
127+
*/
128+
protected void postInitialize() { }
129+
130+
/**
131+
* The first method called in deinitialization.
132+
*/
133+
protected void preDeinitialize() { }
134+
135+
/**
136+
* The last method called in deinitialization.
137+
*/
138+
protected void postDeinitialize() { }
139+
140+
protected void setHistoryProvider(@Nullable HistoryProvider<? extends AbstractComponentHistory> historyProvider) {
141+
this.historyProvider = historyProvider;
142+
}
143+
144+
/**
145+
* Returns the history of the ComponentView.
146+
*/
147+
protected @Nullable AbstractComponentHistory getHistory() {
148+
return history;
149+
}
150+
151+
protected final void restoreHistory() {
152+
var policy = getHistoryPolicy();
153+
logger.debug("{} History policy during restore: {}", getDescriptor().getLogPrefix(), policy);
154+
if (policy != NONE && history != null) {
155+
if (history.isNew()) {
156+
logger.debug("{} History is new. Skipping restoration", getDescriptor().getLogPrefix());
157+
} else {
158+
switch (policy) {
159+
case DATA -> restoreData();
160+
case APPEARANCE -> restoreAppearance();
161+
case ALL -> {
162+
restoreData();
163+
restoreAppearance();
164+
}
165+
default -> throw new AssertionError();
166+
}
167+
}
168+
}
169+
}
170+
171+
/**
172+
* Method copies all data from history to view. This method is called at the beginning of initialization
173+
* when the policy is {@link HistoryPolicy#ALL} or {@link HistoryPolicy#DATA}.
174+
*
175+
*/
176+
protected void restoreData() { }
177+
178+
/**
179+
* Method copies all appearance information from history to view. This method is called at the beginning
180+
* of initialization when the policy is {@link HistoryPolicy#ALL} or {@link HistoryPolicy#APPEARANCE}.
181+
*
182+
*/
183+
protected void restoreAppearance() { }
184+
185+
protected final void saveHistory() {
186+
var policy = getHistoryPolicy();
187+
logger.debug("{} History policy during save: {}", getDescriptor().getLogPrefix(), policy);
188+
switch (policy) {
189+
case DATA -> saveData();
190+
case APPEARANCE -> saveAppearance();
191+
case ALL -> {
192+
saveData();
193+
saveAppearance();
194+
}
195+
case NONE -> { }
196+
default -> throw new AssertionError();
197+
}
198+
}
199+
200+
/**
201+
* Method copies all data from view to history. This method is called at the beginning of deinitialization
202+
* when the policy is {@link HistoryPolicy#ALL} or {@link HistoryPolicy#DATA}.
203+
*
204+
*/
205+
protected void saveData() {
206+
if (this.history != null) {
207+
this.history.setNew(false);
208+
}
209+
}
210+
211+
/**
212+
* Method copies all data from view to history. This method is called at the beginning of deinitialization
213+
* when the policy is {@link HistoryPolicy#ALL} or {@link HistoryPolicy#APPEARANCE}.
214+
*
215+
*/
216+
protected void saveAppearance() {
217+
if (this.history != null) {
218+
this.history.setNew(false);
219+
}
220+
}
221+
222+
protected abstract Descriptor createDescriptor();
223+
224+
void prepareHistory() {
225+
if (this.historyProvider != null) {
226+
this.history = this.historyProvider.provide();
227+
this.historyProvider = null;
228+
}
229+
}
230+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2024-2025 Pavel Castornii.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.techsenger.patternfx.mvp;
18+
19+
/**
20+
*
21+
* @author Pavel Castornii
22+
*/
23+
public abstract class AbstractComponentView<T extends ComponentPresenter<?>> extends AbstractView<T>
24+
implements View {
25+
26+
/**
27+
* Initializes the ComponentView.
28+
*/
29+
protected void initialize() {
30+
// empty
31+
}
32+
33+
/**
34+
* Deiinitializes the ComponentView.
35+
*/
36+
protected void deinitialize() {
37+
// empty
38+
}
39+
}

0 commit comments

Comments
 (0)