Skip to content

Commit b9b1794

Browse files
authored
[28078] Diagnose-Editor: Vorladen, Zeilenabstand, Suchdialog (#952)
1 parent ec5a61b commit b9b1794

8 files changed

Lines changed: 381 additions & 40 deletions

File tree

bundles/ch.elexis.core.findings.ui/src/ch/elexis/core/findings/ui/composites/ConditionComposite.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ private void initDataBinding() {
131131
setCondition(null);
132132
}
133133

134+
public void preload() {
135+
if (textEditor != null && !textEditor.isDisposed()) {
136+
textEditor.preload();
137+
}
138+
}
139+
134140
public Optional<ICondition> getCondition() {
135141
if (conditionValue.getValue() != null) {
136142
conditionValue.getValue().setText(textEditor.getText());
@@ -145,9 +151,7 @@ public void setCondition(final ICondition condition) {
145151
conditionValue.setValue(new ConditionBeanAdapter(condition));
146152
// show coding if present
147153
List<ICoding> coding = this.condition.get().getCoding();
148-
if (coding != null && !coding.isEmpty()) {
149-
textOrCodingFolder.setSelection(1);
150-
}
154+
textOrCodingFolder.setSelection(coding != null && !coding.isEmpty() ? 1 : 0);
151155
} else {
152156
ICondition emptyCondition = FindingsServiceComponent.getService().create(ICondition.class);
153157
emptyCondition.setStatus(ConditionStatus.ACTIVE);

bundles/ch.elexis.core.findings.ui/src/ch/elexis/core/findings/ui/composites/DiagnoseListComposite.java

Lines changed: 124 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
******************************************************************************/
1111
package ch.elexis.core.findings.ui.composites;
1212

13+
import java.lang.reflect.InvocationTargetException;
1314
import java.time.LocalDate;
1415
import java.util.Comparator;
1516
import java.util.List;
@@ -22,6 +23,7 @@
2223
import org.eclipse.jface.action.MenuManager;
2324
import org.eclipse.jface.action.ToolBarManager;
2425
import org.eclipse.jface.dialogs.Dialog;
26+
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
2527
import org.eclipse.jface.resource.ImageDescriptor;
2628
import org.eclipse.jface.viewers.ISelection;
2729
import org.eclipse.jface.viewers.StructuredSelection;
@@ -34,8 +36,10 @@
3436
import org.eclipse.swt.layout.GridLayout;
3537
import org.eclipse.swt.widgets.Composite;
3638
import org.eclipse.swt.widgets.Display;
39+
import org.eclipse.swt.widgets.Shell;
3740
import org.eclipse.swt.widgets.ToolBar;
3841
import org.eclipse.ui.forms.widgets.ScrolledForm;
42+
import org.slf4j.LoggerFactory;
3943

4044
import ca.odell.glazedlists.BasicEventList;
4145
import ca.odell.glazedlists.EventList;
@@ -50,15 +54,16 @@
5054
import ch.elexis.core.findings.ui.services.CodingServiceComponent;
5155
import ch.elexis.core.findings.ui.services.FindingsServiceComponent;
5256
import ch.elexis.core.l10n.Messages;
57+
import ch.elexis.core.lock.types.LockResponse;
5358
import ch.elexis.core.model.IPatient;
5459
import ch.elexis.core.services.LocalConfigService;
5560
import ch.elexis.core.services.holder.ConfigServiceHolder;
5661
import ch.elexis.core.services.holder.ContextServiceHolder;
5762
import ch.elexis.core.text.docx.util.TextUtil;
5863
import ch.elexis.core.ui.icons.Images;
59-
import ch.elexis.core.ui.locks.AcquireLockBlockingUi;
6064
import ch.elexis.core.ui.locks.AcquireLockUi;
6165
import ch.elexis.core.ui.locks.ILockHandler;
66+
import ch.elexis.core.ui.locks.LockResponseHelper;
6267
import ch.elexis.core.ui.util.NatTableFactory;
6368
import ch.elexis.core.ui.util.NatTableWrapper;
6469
import ch.elexis.core.ui.util.NatTableWrapper.IDoubleClickListener;
@@ -76,6 +81,12 @@ public class DiagnoseListComposite extends Composite {
7681
private NatTableWrapper natTableWrapper;
7782
private ToolBarManager toolbarManager;
7883

84+
private ConditionEditDialog editDialog;
85+
86+
private static final String PROPERTY_PRELOAD = "elexis.diagnose.preloadEditor"; //$NON-NLS-1$
87+
88+
private static final int PRELOAD_DELAY_MILLIS = 1500;
89+
7990
private EventList<ICondition> dataList = new BasicEventList<>();
8091

8192
@SuppressWarnings("deprecation")
@@ -120,32 +131,36 @@ private Object getAlternativeFormattedText(ICondition condition) {
120131

121132
ConditionStatus status = condition.getStatus();
122133
text.append(status.getLocalized());
123-
text.append("<br/>");
134+
StringBuilder secondLine = new StringBuilder();
124135
Optional<String> start = condition.getStart();
125136
if (start.isPresent() && StringUtils.isNotBlank(start.get())) {
126-
text.append(start.get());
137+
secondLine.append(start.get());
127138
}
128139

129140
Optional<String> end = condition.getEnd();
130141
if (end.isPresent() && StringUtils.isNotBlank(end.get())) {
131-
text.append(" - ").append(end.get());
142+
secondLine.append(" - ").append(end.get());
132143
}
133144

134145
List<ICoding> codings = condition.getCoding();
135146
if (codings != null && !codings.isEmpty()) {
136147
for (ICoding iCoding : codings) {
137-
text.append(" [").append(CodingServiceComponent.getService().getShortLabel(iCoding))
148+
secondLine.append(" [")
149+
.append(CodingServiceComponent.getService().getShortLabel(iCoding))
138150
.append("]");
139151
}
140152
}
153+
if (secondLine.length() > 0) {
154+
text.append("<br/>").append(secondLine);
155+
}
141156
text.append("</strong>");
142157

143158
boolean hasText = condition.getText().isPresent()
144159
&& StringUtils.isNotBlank(condition.getText().get());
145160
boolean hasNotes = !condition.getNotes().isEmpty();
146161

147162
if (hasText || hasNotes) {
148-
text.append("<br/><br/>");
163+
text.append("<p><br/>");
149164
}
150165

151166
if (hasText) {
@@ -162,8 +177,6 @@ private Object getAlternativeFormattedText(ICondition condition) {
162177
}
163178
}
164179

165-
text.append("<br/>");
166-
167180
return text.toString();
168181
}
169182

@@ -226,23 +239,11 @@ public void setDataValue(ICondition condition, int arg1, Object arg2) {
226239
public void doubleClick(NatTableWrapper source, ISelection selection) {
227240
if (selection instanceof StructuredSelection && !selection.isEmpty()) {
228241
ICondition condition = (ICondition) ((StructuredSelection) selection).getFirstElement();
229-
AcquireLockBlockingUi.aquireAndRun(condition, new ILockHandler() {
230-
@Override
231-
public void lockFailed() {
232-
// do nothing
233-
}
234-
235-
@Override
236-
public void lockAcquired() {
237-
ConditionEditDialog dialog = new ConditionEditDialog(condition,
238-
Display.getDefault().getActiveShell());
239-
if (dialog.open() == Dialog.OK) {
240-
dialog.getCondition().ifPresent(c -> {
241-
source.getNatTable().refresh();
242-
});
243-
}
244-
}
245-
});
242+
if (editDialog != null && editDialog.isOpen()) {
243+
editDialog.getShell().setActive();
244+
return;
245+
}
246+
editCondition(condition, source);
246247
}
247248
}
248249
});
@@ -258,6 +259,95 @@ public void lockAcquired() {
258259
ToolBar toolbar = toolbarManager.createControl(this);
259260
toolbar.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
260261
toolbar.setBackground(parent.getBackground());
262+
263+
addDisposeListener(e -> disposeEditDialog());
264+
}
265+
266+
/**
267+
* Locks the condition, edits it, releases the lock. The lock is acquired exactly
268+
* as {@code AcquireLockBlockingUi} does it blocking, with a cancelable progress
269+
* dialog but that dialog is closed again before the editor opens, and the lock
270+
* is only released once editing is done.
271+
* <p>
272+
* The order is what makes a kept editor possible at all. {@code AcquireLockBlockingUi}
273+
* calls its handler while its progress dialog is still up, and that dialog is
274+
* application modal and disposed right afterwards: an editor built next to it would
275+
* be blocked by its modality, and one built below it would be disposed with it.
276+
* Since {@link ICondition} is an {@code Identifiable}, it takes the overload without
277+
* the standalone shortcut, so that progress dialog appears even without a lock server.
278+
*/
279+
private void editCondition(ICondition condition, NatTableWrapper source) {
280+
LockResponse lockResponse = acquireLockBlocking(condition);
281+
if (lockResponse == null) {
282+
return;
283+
}
284+
if (!lockResponse.isOk()) {
285+
LockResponseHelper.showInfo(lockResponse, condition, LoggerFactory.getLogger(getClass()));
286+
return;
287+
}
288+
try {
289+
if (openEditDialog(condition, condition.getCategory(), getShell()) == Dialog.OK && editDialog != null) {
290+
editDialog.getCondition().ifPresent(c -> {
291+
source.getNatTable().refresh();
292+
});
293+
}
294+
} finally {
295+
LocalLockServiceHolder.get().releaseLock(lockResponse.getLockInfo());
296+
}
297+
}
298+
299+
private LockResponse acquireLockBlocking(ICondition condition) {
300+
LockResponse[] result = new LockResponse[1];
301+
try {
302+
new ProgressMonitorDialog(getShell()).run(true, true,
303+
monitor -> result[0] = LocalLockServiceHolder.get().acquireLockBlocking(condition, 30, monitor));
304+
} catch (InvocationTargetException | InterruptedException e) {
305+
LoggerFactory.getLogger(getClass()).warn("Exception during acquire lock.", e); //$NON-NLS-1$
306+
return null;
307+
}
308+
return result[0];
309+
}
310+
311+
private int openEditDialog(ICondition condition, ConditionCategory category, Shell parentShell) {
312+
if (editDialog != null && !editDialog.canReuseFor(parentShell, category)) {
313+
disposeEditDialog();
314+
}
315+
if (editDialog == null) {
316+
editDialog = condition != null ? new ConditionEditDialog(condition, parentShell)
317+
: new ConditionEditDialog(category, parentShell);
318+
editDialog.setReusable(true);
319+
} else {
320+
editDialog.setCondition(condition);
321+
}
322+
return editDialog.open();
323+
}
324+
325+
private void disposeEditDialog() {
326+
if (editDialog != null) {
327+
editDialog.dispose();
328+
editDialog = null;
329+
}
330+
}
331+
332+
private void preloadEditDialog() {
333+
if (editDialog != null || isDisposed() || getShell() == null
334+
|| !Boolean.parseBoolean(System.getProperty(PROPERTY_PRELOAD, Boolean.TRUE.toString()))) {
335+
return;
336+
}
337+
getDisplay().timerExec(PRELOAD_DELAY_MILLIS, () -> {
338+
if (editDialog != null || isDisposed() || getShell() == null || getShell().isDisposed()) {
339+
return;
340+
}
341+
try {
342+
ConditionEditDialog preloaded = new ConditionEditDialog(ConditionCategory.PROBLEMLISTITEM, getShell());
343+
preloaded.setReusable(true);
344+
preloaded.preload();
345+
editDialog = preloaded;
346+
} catch (Exception e) {
347+
LoggerFactory.getLogger(getClass()).warn("Could not preload the condition dialog", e); //$NON-NLS-1$
348+
disposeEditDialog();
349+
}
350+
});
261351
}
262352

263353
private static void appendFormattedLine(StringBuilder text, String line) {
@@ -286,6 +376,8 @@ public int compare(ICondition left, ICondition right) {
286376
dataList.addAll(conditions);
287377
natTableWrapper.getNatTable().refresh();
288378

379+
preloadEditDialog();
380+
289381
Display.getDefault().asyncExec(() -> {
290382
if (!isDisposed()) {
291383
Composite parent = getParent();
@@ -396,9 +488,13 @@ public String getText() {
396488
public void run() {
397489
IPatient selectedPatient = ContextServiceHolder.get().getActivePatient().orElse(null);
398490
if (selectedPatient != null) {
399-
ConditionEditDialog dialog = new ConditionEditDialog(ConditionCategory.PROBLEMLISTITEM, getShell());
400-
if (dialog.open() == Dialog.OK) {
401-
dialog.getCondition().ifPresent(c -> {
491+
if (editDialog != null && editDialog.isOpen()) {
492+
editDialog.getShell().setActive();
493+
return;
494+
}
495+
if (openEditDialog(null, ConditionCategory.PROBLEMLISTITEM, getShell()) == Dialog.OK
496+
&& editDialog != null) {
497+
editDialog.getCondition().ifPresent(c -> {
402498
c.setPatientId(selectedPatient.getId());
403499
FindingsServiceComponent.getService().saveFinding(c);
404500
// touch after creation

0 commit comments

Comments
 (0)