Statistics
| Revision:

gvsig-tools / org.gvsig.tools / library / trunk / org.gvsig.tools / org.gvsig.tools.dynform / org.gvsig.tools.dynform.spi / src / main / java / org / gvsig / tools / dynform / spi / dynform / AbstractJDynForm.java @ 3087

History | View | Annotate | Download (22.9 KB)

1
package org.gvsig.tools.dynform.spi.dynform;
2

    
3
import java.awt.BorderLayout;
4
import java.awt.Color;
5
import java.awt.Component;
6
import java.awt.Dimension;
7
import java.awt.Toolkit;
8
import java.awt.event.MouseAdapter;
9
import java.awt.event.MouseEvent;
10
import java.io.OutputStream;
11
import java.nio.charset.StandardCharsets;
12
import java.text.NumberFormat;
13
import java.util.ArrayList;
14
import java.util.HashMap;
15
import java.util.HashSet;
16
import java.util.Iterator;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Objects;
20
import java.util.Set;
21
import javax.swing.Action;
22
import javax.swing.BorderFactory;
23
import javax.swing.JComponent;
24
import javax.swing.JLabel;
25
import javax.swing.JOptionPane;
26
import javax.swing.JPanel;
27
import javax.swing.JScrollPane;
28
import javax.swing.JViewport;
29
import javax.swing.SwingUtilities;
30
import org.apache.commons.io.IOUtils;
31
import org.apache.commons.text.StringEscapeUtils;
32
import org.apache.commons.lang3.StringUtils;
33
import org.gvsig.tools.ToolsLocator;
34
import org.gvsig.tools.dataTypes.CoercionException;
35
import org.gvsig.tools.dataTypes.DataType;
36
import org.gvsig.tools.dataTypes.DataTypes;
37
import org.gvsig.tools.dispose.DisposeUtils;
38
import org.gvsig.tools.dynform.DynFormDefinition;
39
import org.gvsig.tools.dynform.DynFormFieldDefinition;
40
import org.gvsig.tools.dynform.JDynForm;
41
import org.gvsig.tools.dynform.JDynFormField;
42
import org.gvsig.tools.dynform.spi.DynFormSPIManager;
43
import org.gvsig.tools.dynform.spi.dynformfield.AbstractJDynFormFieldWithValueList;
44
import org.gvsig.tools.dynobject.DynObject;
45
import org.gvsig.tools.dynobject.Tags;
46
import org.gvsig.tools.i18n.I18nManager;
47
import org.gvsig.tools.identitymanagement.SimpleIdentity;
48
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
49
import org.gvsig.tools.script.Script;
50
import org.gvsig.tools.script.ScriptManager;
51
import org.gvsig.tools.swing.api.ToolsSwingUtils;
52
import org.gvsig.tools.util.PropertiesSupportHelper;
53
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
55

    
56
@SuppressWarnings("UseSpecificCatch")
57
public abstract class AbstractJDynForm implements JDynForm {
58

    
59
    protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractJDynForm.class);
60
    
61
    private final DynFormSPIManager manager;
62
    private final DynFormDefinition definition;
63
    private final JDynFormFactory factory;
64

    
65
    private DynFormContext context;
66

    
67
    private int formWidth = -1;
68
    private int formHeight = -1;
69
    private int layoutMode = USE_PLAIN;
70
    private JLabel jlabel_messages = null;
71
    private boolean readOnly = true;
72
    private Set listeners = null;
73
    private boolean useScrollBars = true;
74
    private final Map<String, List<Action>> customActions;
75
    protected JComponent contents = null;
76
    protected DynObject values = null;
77
    protected boolean border;
78
    private final PropertiesSupportHelper propertiesHelper = new PropertiesSupportHelper();
79
    private Script script;
80
    private boolean script_initialized = false;
81

    
82
    @SuppressWarnings("OverridableMethodCallInConstructor")
83
    public AbstractJDynForm(
84
            DynFormSPIManager manager,
85
            JDynFormFactory factory,
86
            DynFormDefinition definition,
87
            DynFormContext context
88
    ) {
89
        this.manager = manager;
90
        this.factory = factory;
91
        this.definition = definition;
92
        this.context = context;
93
        this.listeners = new HashSet();
94
        this.customActions = new HashMap();
95
        if (definition != null) {
96
            this.loadDefaultValuesFromTags(definition.getTags());
97
            SimpleIdentity user = ToolsLocator.getIdentityManager().getCurrentIdentity();
98
            if( !user.canWrite(this, definition.getName()) ) {
99
                this.readOnly = true;
100
            }
101
        }
102
    }
103

    
104
    @Override
105
    public Script getScript() {
106
        if( script_initialized ) {
107
            return script;
108
        }
109
        ResourcesStorage resources = null;
110
        try {
111
            resources = this.context.getResourcesStorage();
112
            if( resources==null ) {
113
                this.script = null;
114
                this.script_initialized = true;
115
                return null;
116
            }
117
            ResourcesStorage.Resource res = resources.getResource("jfrms");
118
            if( res == null || !res.exists() ) {
119
                this.script = null;
120
                this.script_initialized = true;
121
                return null;
122
            }
123
            String source = IOUtils.toString(res.asInputStream());
124
            if( StringUtils.isEmpty(source) ) {
125
                this.script = null;
126
                this.script_initialized = true;
127
                return null;
128
            }
129
            ScriptManager scriptManager = this.context.getScriptManager();
130
            if( scriptManager==null ) {
131
                this.script = null;
132
                this.script_initialized = true;
133
                return null;
134
            }
135
            this.script = scriptManager.createScript(this.definition.getName(), source, null);
136
            this.script_initialized = true;
137
            return script;
138
        } catch (Exception ex) {
139
            LOGGER.warn("Can't load resource jfrms.", ex);
140
            this.script = null;
141
            this.script_initialized = true;
142
            return null;
143
        } finally {
144
            DisposeUtils.disposeQuietly(resources);
145
        }
146
    }
147
    
148
    public boolean isScriptReadOnly() {
149
        ResourcesStorage resources = null;
150
        ResourcesStorage.Resource res = null;
151
        try {
152
            resources = this.context.getResourcesStorage();
153
            if( resources==null ) {
154
                return true;
155
            }
156
            res = resources.getResource("jfrms");
157
            if( res == null ) {
158
                return true;
159
            }
160
            return res.isReadOnly();
161

    
162
        } catch (Exception ex) {
163
            LOGGER.warn("Can't check if script resource jfrms is read-only.", ex);
164
            return true;
165
            
166
        } finally {
167
            IOUtils.closeQuietly(res);
168
            DisposeUtils.disposeQuietly(resources);
169
        }
170
    }
171
    
172
    @Override
173
    public void putScript(String source) {
174
        ResourcesStorage resources = null;
175
        ResourcesStorage.Resource res = null;
176
        OutputStream os = null;
177
        try {
178
            ScriptManager scriptManager = this.context.getScriptManager();
179
            if( scriptManager==null ) {
180
                throw new RuntimeException("Can't get the scripting manager.");
181
            }
182
            this.script = scriptManager.createScript(this.definition.getName(), source, null);
183
            this.script_initialized = true;
184

    
185
            resources = this.context.getResourcesStorage();
186
            if( resources==null ) {
187
                throw new RuntimeException("Can't get the resources storage.");
188
            }
189
            res = resources.getResource("jfrms");
190
            if( res == null ) {
191
                throw new RuntimeException("Can't get the resource of this form.");
192
            }
193
            if( res.isReadOnly() ) {
194
                throw new RuntimeException("Can't modify the resource, is read-only.");
195
            }
196
            os = res.asOutputStream();
197
            IOUtils.write(source, os, StandardCharsets.UTF_8);
198

    
199
        } catch (Exception ex) {
200
            LOGGER.warn("Can't save resource jfrms.", ex);
201
        } finally {
202
            IOUtils.closeQuietly(os);
203
            IOUtils.closeQuietly(res);
204
            DisposeUtils.disposeQuietly(resources);
205
        }
206
    }
207
    
208
    @Override
209
    public void callUserEvent(String name, Object...args) {
210
        Script theScript = this.getScript();
211
        if( theScript==null ) {
212
            return;
213
        }
214
        try {
215
            theScript.invokeFunction(name, args);
216
        } catch(NoSuchMethodException ex) {
217
            // Do nothing
218
        } catch(Exception ex) {
219
            LOGGER.warn("Error calling form event '"+name+"'.", ex);
220
        }
221
    }
222
    
223
    @Override
224
    public Object callUserFunction(String function, Object...args) throws Exception {
225
        Script theScript = this.getScript();
226
        if( theScript==null ) {
227
            throw new RuntimeException("Can't exists user code associated to this form.");
228
        }
229
        return theScript.invokeFunction(function, args);
230
    } 
231

    
232
    public static int getLayoutFromTags(Tags tags) {
233
        String layoutMode = (String) tags.get(
234
                DynFormSPIManager.TAG_DYNFORM_LAYOUTMODE, 
235
                DataTypes.STRING, 
236
                DynFormSPIManager.TAG_DYNFORM_LAYOUTMODE_VALUE_PLAIN
237
        );
238
        if (!StringUtils.isEmpty(layoutMode)) {
239
            if (layoutMode.equalsIgnoreCase("0")
240
                    || layoutMode.equalsIgnoreCase(DynFormSPIManager.TAG_DYNFORM_LAYOUTMODE_VALUE_PLAIN)) {
241
                return JDynForm.USE_PLAIN;
242
            } else if (layoutMode.equalsIgnoreCase("1")
243
                    || layoutMode.equalsIgnoreCase(DynFormSPIManager.TAG_DYNFORM_LAYOUTMODE_VALUE_TABS)) {
244
                return JDynForm.USE_TABS;
245
            } else if (layoutMode.equalsIgnoreCase("2")
246
                    || layoutMode.equalsIgnoreCase(DynFormSPIManager.TAG_DYNFORM_LAYOUTMODE_VALUE_SEPARATORS)) {
247
                return JDynForm.USE_SEPARATORS;
248
            }
249
        }
250
        return JDynForm.USE_PLAIN;
251
    }
252

    
253
    public void loadDefaultValuesFromTags(Tags tags) {
254
        this.setLayoutMode(getLayoutFromTags(tags));
255

    
256
        try {
257
            String s = tags.getString(DynFormSPIManager.TAG_DYNFORM_WIDTH);
258
            this.formWidth = NumberFormat.getInstance().parse(s).intValue();
259
            if( StringUtils.endsWithAny(s, "ch","char","cols","columns") ) {
260
                this.formWidth = ToolsSwingUtils.cols2px(this.formWidth);
261
            }
262
        } catch (Exception ex) {
263
        }
264
        try {
265
            String s = tags.getString(DynFormSPIManager.TAG_DYNFORM_HEIGHT);
266
            this.formHeight = NumberFormat.getInstance().parse(s).intValue();
267
            if( StringUtils.endsWithAny(s, "ch","char","rows","lines") ) {
268
                this.formHeight = ToolsSwingUtils.rows2px(this.formHeight);
269
            }
270
        } catch (Exception ex) {
271
        }
272
        try {
273
            this.border = tags.getBoolean(DynFormSPIManager.TAG_DYNFORM_BORDER);
274
        } catch (CoercionException ex) {
275
        }
276
        try {
277
            this.useScrollBars = tags.getBoolean(DynFormSPIManager.TAG_DYNFORM_USESCROLLBARS);
278
        } catch (CoercionException ex) {
279
        }
280
        try {
281
            this.readOnly = tags.getBoolean(DynFormSPIManager.TAG_DYNFORM_READONLY);
282
        } catch (CoercionException ex) {
283
        }
284
    }
285

    
286
    public DynFormSPIManager getServiceManager() {
287
        return this.manager;
288
    }
289

    
290
    @Override
291
    public JComponent asJComponent() {
292
        if (this.contents == null) {
293
            this.initComponents();
294
        }
295
        return this.contents;
296
    }
297

    
298
    protected void initComponents() {
299
        if (this.contents == null) {
300
            this.contents = addScrollsAndMessageBar(this.getFieldsContainer());
301
            if (this.values != null) {
302
                this.setValues(values);
303
            }
304
            if (this.border) {
305
                this.contents.setBorder(BorderFactory.createLineBorder(Color.GRAY));
306
            }
307
            message();
308
        }
309
    }
310

    
311
    protected boolean isContentsInitialized() {
312
        return this.contents != null;
313
    }
314

    
315
    @Override
316
    public void addListener(JDynFormListener listener) {
317
        this.listeners.add(listener);
318
    }
319

    
320
    @Override
321
    public void removeListener(JDynFormListener listener) {
322
        this.listeners.remove(listener);
323
    }
324

    
325
    public JLabel getMessagesJLabel() {
326
        if (this.jlabel_messages == null) {
327
            this.jlabel_messages = new JLabel();
328
            this.jlabel_messages.addMouseListener(new MouseAdapter() {
329
                @Override
330
                public void mouseClicked(MouseEvent evt) {
331
                    int count = evt.getClickCount();
332
                    if (count == 2) {
333
                        JOptionPane.showMessageDialog(contents, jlabel_messages.getText(), "Status", JOptionPane.INFORMATION_MESSAGE);
334
                    }
335
                }
336
            });
337
        }
338
        return this.jlabel_messages;
339
    }
340

    
341
    @Override
342
    public void setShowMessageStatus(boolean showMessageStatus) {
343
        this.getMessagesJLabel().setVisible(showMessageStatus);
344
    }
345

    
346
    @Override
347
    public boolean isShowMessageStatus() {
348
        return this.getMessagesJLabel().isVisible();
349
    }
350

    
351
    @Override
352
    public void message() {
353
        this.getMessagesJLabel().setText(" ");
354
    }
355

    
356
    @Override
357
    public void message(String msg) {
358
        this.getMessagesJLabel().setText(msg);
359
        fireMessageEvent(msg);
360
    }
361

    
362
    protected void fireMessageEvent(String message) {
363
        Iterator it = this.listeners.iterator();
364
        while (it.hasNext()) {
365
            JDynFormListener listener = (JDynFormListener) it.next();
366
            try {
367
                listener.message(message);
368
            } catch (Exception ex) {
369
                LOGGER.info("Error calling listener " + listener.toString()
370
                        + "(" + listener.getClass().getName() + ") from "
371
                        + this.toString() + "(" + this.getClass().getName()
372
                        + ").", ex);
373
            }
374
        }
375
    }
376

    
377
    protected void fireFieldChangeEvent(JDynFormField field) {
378
        Iterator it = this.listeners.iterator();
379
        while (it.hasNext()) {
380
            JDynFormListener listener = (JDynFormListener) it.next();
381
            try {
382
                listener.fieldChanged(field);
383
            } catch (Exception ex) {
384
                LOGGER.info("Error calling listener " + listener.toString()
385
                        + "(" + listener.getClass().getName() + ") from "
386
                        + this.toString() + "(" + this.getClass().getName()
387
                        + ").", ex);
388
            }
389
        }
390
    }
391

    
392
    protected JPanel addScrollsAndMessageBar(JComponent formPanel) {
393
        formPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
394
        JScrollPane scroll = new JScrollPane(formPanel);
395
        
396
        scroll.getVerticalScrollBar().setBlockIncrement(30);
397
        scroll.getVerticalScrollBar().setUnitIncrement(10);
398
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
399
        Dimension size = formPanel.getPreferredSize();
400
        if( this.formHeight<100 ) {
401
            if( size.height>screenSize.height-100 ) {
402
                this.formHeight = screenSize.height-150;
403
            } else {
404
                this.formHeight = size.height;
405
            }
406
        }
407
        if( this.formWidth<100 ) {
408
            if( size.width>800 ) {
409
                this.formWidth = 800;
410
            } else {
411
                this.formWidth = size.width;
412
            }
413
        }
414
        
415
        if (useScrollBars) {
416
            int scrollBarWidth = scroll.getVerticalScrollBar().getPreferredSize().width;
417
            scroll.setPreferredSize(new Dimension(formWidth+4, formHeight+4));
418
//            formPanel.setPreferredSize(new Dimension(formWidth-scrollBarWidth, formHeight));
419
        } else {
420
            scroll.setPreferredSize(new Dimension(formWidth, formHeight));
421
        }
422
        scroll.setBorder(BorderFactory.createEmptyBorder());
423
        JPanel jpanel = new JPanel();
424
        jpanel.setLayout(new BorderLayout());
425
        jpanel.add(scroll, BorderLayout.CENTER);
426
        jpanel.add(getMessagesJLabel(), BorderLayout.PAGE_END);
427
        return jpanel;
428
    }
429

    
430
    @Override
431
    public int getLayoutMode() {
432
        return this.layoutMode;
433
    }
434

    
435
    @Override
436
    public void setLayoutMode(int layoutMode) {
437
        if (layoutMode < 0 || layoutMode > USE_SEPARATORS) {
438
            throw new IllegalArgumentException("layoutMode (" + layoutMode + ") out of range. Valid values are 0 .. " + USE_SEPARATORS + ".");
439
        }
440
        this.layoutMode = layoutMode;
441
    }
442

    
443
    @Override
444
    public boolean isReadOnly() {
445
        return readOnly;
446
    }
447

    
448
    @Override
449
    public void setReadOnly(boolean readOnly) {
450
        this.readOnly = readOnly;
451
    }
452

    
453
    @Override
454
    public int getFormWidth() {
455
        if (this.contents == null) {
456
            return this.formWidth;
457
        } else {
458
            JViewport port = ((JScrollPane) this.asJComponent()).getViewport();
459
            Component comp = (Component) port.getView();
460
            return comp.getWidth();
461
        }
462
    }
463

    
464
    @Override
465
    public int getFormHeight() {
466
        if (this.contents == null) {
467
            return this.formHeight;
468
        } else {
469
            JViewport port = ((JScrollPane) this.asJComponent()).getViewport();
470
            Component comp = (Component) port.getView();
471
            return comp.getHeight();
472
        }
473
    }
474

    
475
    @Override
476
    public void setFormSize(int width, int height) {
477
        this.formHeight = height;
478
        this.formWidth = width;
479
        if (this.contents != null) {
480
            this.asJComponent().setPreferredSize(new Dimension(width, height));
481
        }
482
    }
483
    public void configurePopupMenu(JDynFormField jfield) {
484
        DynFormFieldDefinition fieldDefinition = jfield.getDefinition();
485
        List<Action> customActions = getCustomActionsForDataType(fieldDefinition.getDataType());
486
        if (customActions != null && !customActions.isEmpty()) {
487
            for (Action customAction : customActions) {
488
                if (customAction != null) {
489
                    jfield.addActionToPopupMenu((String) customAction.getValue(Action.NAME), customAction);
490
                } else {
491
                    jfield.addSeparatorToPopupMenu();
492
                }
493
            }
494
        }
495
        this.getServiceManager().configurePopupMenu(jfield);
496
    }
497
    
498
    protected List<Action> getCustomActionsForDataType(DataType dataType) {
499
        return (List<Action>) customActions.get(dataType.getName());
500
    }
501

    
502
    @Override
503
    public void addActionToPopupMenu(DataType tipo, String name, Action action) {
504
        List<Action> acts = this.getCustomActionsForDataType(tipo);
505
        action.putValue(Action.NAME, name);
506
        if (acts == null) {
507
            List<Action> aux = new ArrayList<>();
508
            aux.add(action);
509
            customActions.put(tipo.getName(), aux);
510
        } else {
511
            acts.add(action);
512
        }
513
    }
514

    
515
    @Override
516
    public void addSeparatorToPopupMenu(DataType tipo) {
517
        List<Action> acts = this.getCustomActionsForDataType(tipo);
518
        if (acts == null) {
519
            List<Action> aux = new ArrayList<>();
520
            aux.add(null);
521
            customActions.put(tipo.getName(), aux);
522
        } else {
523
            acts.add(null);
524
        }
525
    }
526

    
527
    @Override
528
    public DynFormDefinition getDefinition() {
529
        return this.definition;
530
    }
531

    
532
    @Override
533
    public boolean getUseScrollBars() {
534
        return useScrollBars;
535
    }
536

    
537
    @Override
538
    public void setUseScrollBars(boolean usesScrolls) {
539
        this.useScrollBars = usesScrolls;
540
    }
541

    
542
    public void setBorder(boolean border) {
543
        this.border = border;
544
        if (this.isContentsInitialized() && border) {
545
            this.asJComponent().setBorder(BorderFactory.createLineBorder(Color.GRAY));
546
        }
547
    }
548

    
549
    @Override
550
    public JDynFormField getField(String fieldName) {
551
        return null;
552
    }
553

    
554
    @Override
555
    public final JDynFormField get(String key) {
556
        return this.getField(key);
557
    }
558
    
559
    @Override
560
    public Object getProperty(String key) {
561
        return this.propertiesHelper.getProperty(key);
562
    }
563

    
564
    @Override
565
    public void setProperty(String key, Object obj) {
566
        this.propertiesHelper.setProperty(key, obj);
567
    }
568

    
569
    @Override
570
    public Map<String, Object> getProperties() {
571
        return this.propertiesHelper.getProperties();
572
    }
573

    
574
    @Override
575
    public DynFormContext getContext() {
576
        return this.context;
577
    }
578

    
579
    @Override
580
    public void setContext(DynFormContext context) {
581
        this.context = context;
582
    }
583

    
584
    @Override
585
    public String toHtml() {
586
        I18nManager i18n = ToolsLocator.getI18nManager();
587
        List<String> groups = this.getDefinition().getGroups();
588

    
589
        StringBuilder builder = new StringBuilder();
590
        builder.append("<html>\n");
591
        builder.append("<body>\n");
592
        builder.append("<table style=\"border: none;\" cellspacing=\"2\" cellpadding=\"0\">\n");
593

    
594
        for (String group : groups) {
595
            String tablabel = group;
596
            if (StringUtils.isBlank(tablabel)) {
597
                tablabel = i18n.getTranslation("General");
598
            } else {
599
                tablabel = i18n.getTranslation(tablabel);            
600
            }
601
            builder.append("<tr>\n");
602
            builder.append("<td colspan=\"2\">\n<br/><i>");
603
            builder.append(StringEscapeUtils.escapeHtml3(tablabel));
604
            builder.append("</i>");
605
//            builder.append("<br/><hr/>\n");
606
            builder.append("</td>\n");
607
            builder.append("</tr>\n");            
608
            List<DynFormFieldDefinition> fields = this.getDefinition().getDefinitions(group);                
609
            for (DynFormFieldDefinition fieldDefinition : fields) {
610
                if( fieldDefinition.isHidden() ) {
611
                    continue;
612
                }
613
                JDynFormField jfield = this.getField(fieldDefinition.getName());
614
                if( jfield == null ) {
615
                    continue; // ??????
616
                }
617
                String value = jfield.toHTML();
618
                if( value == null ) {
619
                    if (fieldDefinition.isHidden() || fieldDefinition.getDataType().isContainer()) {
620
                        continue;
621
                    } 
622
                    if( jfield instanceof AbstractJDynFormFieldWithValueList ) {
623
                        value = ((AbstractJDynFormFieldWithValueList)jfield).getFromJComponent();
624
                    } else {
625
                        try {
626
                            value = Objects.toString(jfield.getValue(),"");
627
                        } catch(Exception e) {
628
                            value = "#ERROR#";
629
                        }
630
                    }
631
                    value = StringEscapeUtils.escapeHtml3(value);
632
                }
633
                builder.append("<tr>\n");
634
                if(  jfield.useEmptyLabel() ) {
635
                    builder.append("<td colspan=\"2\">\n");
636
                    builder.append(value);
637
                    builder.append("</td>\n");
638
                } else {
639
                    builder.append("<td valign=\"top\" nowrap style=\"white-space:nowrap;\">\n");
640
                    if( fieldDefinition.isMandatory() ) {
641
                        builder.append("<b>");
642
                        builder.append(StringEscapeUtils.escapeHtml3(fieldDefinition.getLabel()));
643
                        builder.append("</b>");
644
                    } else {
645
                        builder.append(StringEscapeUtils.escapeHtml3(fieldDefinition.getLabel()));
646
                    }
647
                    builder.append(": ");
648
                    builder.append("</td>\n");
649

    
650
                    builder.append("<td>\n");
651
                    builder.append(value);
652
                    builder.append("</td>\n");
653
                }
654
                builder.append("</tr>\n");
655
            }
656
        }
657

    
658
        builder.append("</table>\n");
659
        builder.append("</body>\n");
660
        builder.append("</html>\n");
661

    
662
        return builder.toString();
663
    }
664

    
665
}