View Javadoc
1   package fr.ifremer.tutti.ui.swing.util;
2   
3   /*
4    * #%L
5    * Tutti :: UI
6    * %%
7    * Copyright (C) 2012 - 2014 Ifremer
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as
11   * published by the Free Software Foundation, either version 3 of the 
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public 
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/gpl-3.0.html>.
22   * #L%
23   */
24  
25  import com.google.common.base.Preconditions;
26  import com.google.common.collect.Sets;
27  import fr.ifremer.tutti.LabelAware;
28  import fr.ifremer.tutti.TuttiConfiguration;
29  import fr.ifremer.tutti.persistence.entities.data.SampleCategory;
30  import fr.ifremer.tutti.persistence.entities.referential.Species;
31  import fr.ifremer.tutti.service.DecoratorService;
32  import fr.ifremer.tutti.service.PersistenceService;
33  import fr.ifremer.tutti.service.TuttiDataContext;
34  import fr.ifremer.tutti.service.ValidationService;
35  import fr.ifremer.tutti.service.catches.ValidateCruiseOperationsService;
36  import fr.ifremer.tutti.type.WeightUnit;
37  import fr.ifremer.tutti.ui.swing.TuttiUIContext;
38  import fr.ifremer.tutti.ui.swing.content.MainUI;
39  import fr.ifremer.tutti.ui.swing.content.MainUIHandler;
40  import fr.ifremer.tutti.ui.swing.util.actions.ShowComboBoxPopupActions;
41  import fr.ifremer.tutti.ui.swing.util.attachment.ButtonAttachment;
42  import fr.ifremer.tutti.ui.swing.util.computable.ComputableDataEditor;
43  import jaxx.runtime.swing.JAXXWidgetUtil;
44  import jaxx.runtime.swing.editor.cell.NumberCellEditor;
45  import jaxx.runtime.validator.swing.SwingValidator;
46  import org.apache.commons.logging.Log;
47  import org.apache.commons.logging.LogFactory;
48  import org.jdesktop.swingx.JXTable;
49  import org.jdesktop.swingx.JXTitledPanel;
50  import org.jdesktop.swingx.decorator.FontHighlighter;
51  import org.jdesktop.swingx.decorator.HighlightPredicate;
52  import org.jdesktop.swingx.decorator.Highlighter;
53  import org.jdesktop.swingx.table.TableColumnExt;
54  import org.nuiton.decorator.Decorator;
55  import org.nuiton.jaxx.application.swing.AbstractApplicationUIHandler;
56  import org.nuiton.jaxx.application.swing.table.AbstractApplicationTableModel;
57  import org.nuiton.jaxx.application.swing.table.ColumnIdentifier;
58  import org.nuiton.jaxx.application.swing.util.ActionListCellRenderer;
59  import org.nuiton.jaxx.widgets.number.NumberEditor;
60  import org.nuiton.validator.bean.simple.SimpleBeanValidator;
61  
62  import javax.swing.AbstractButton;
63  import javax.swing.DefaultComboBoxModel;
64  import javax.swing.JButton;
65  import javax.swing.JComboBox;
66  import javax.swing.JComponent;
67  import javax.swing.JLabel;
68  import javax.swing.JTable;
69  import javax.swing.JTextField;
70  import javax.swing.border.LineBorder;
71  import javax.swing.table.TableCellEditor;
72  import javax.swing.table.TableCellRenderer;
73  import javax.swing.table.TableColumnModel;
74  import java.awt.Color;
75  import java.awt.Component;
76  import java.awt.Font;
77  import java.awt.event.MouseAdapter;
78  import java.awt.event.MouseEvent;
79  import java.beans.PropertyChangeEvent;
80  import java.beans.PropertyChangeListener;
81  import java.util.List;
82  import java.util.Objects;
83  import java.util.Set;
84  
85  import static org.nuiton.i18n.I18n.t;
86  
87  /**
88   * Contract of any UI handler.
89   *
90   * @author Tony Chemit - chemit@codelutin.com
91   * @since 0.1
92   */
93  public abstract class AbstractTuttiUIHandler<M, UI extends TuttiUI<M, ?>> extends AbstractApplicationUIHandler<M, UI> implements UIMessageNotifier {
94  
95      /** Logger. */
96      private static final Log log =
97              LogFactory.getLog(AbstractTuttiUIHandler.class);
98  
99      public static final String CAN_EDIT = "_canEdit_";
100 
101     //------------------------------------------------------------------------//
102     //-- Public methods                                                     --//
103     //------------------------------------------------------------------------//
104 
105     @Override
106     public void showInformationMessage(String message) {
107         getContext().showInformationMessage(message);
108     }
109 
110     @Override
111     public TuttiUIContext getContext() {
112         return (TuttiUIContext) super.getContext();
113     }
114 
115     public TuttiDataContext getDataContext() {
116         return getContext().getDataContext();
117     }
118 
119     public TuttiConfiguration getConfig() {
120         return getContext().getConfig();
121     }
122 
123     public PersistenceService getPersistenceService() {
124         return getContext().getPersistenceService();
125     }
126 
127     public ValidationService getValidationService() {
128         return getContext().getValidationService();
129     }
130 
131     public ValidateCruiseOperationsService getValidateCruiseOperationsService() {
132         return getContext().getValidateCruiseOperationsService();
133     }
134 
135     @Override
136     public Component getTopestUI() {
137         Component result;
138         //        if (actionUI.isVisible()) {
139         result = getContext().getActionUI();
140 //        } else {
141 //            result = getContext().getMainUI();
142 //        }
143         return result;
144     }
145 
146     public void clearValidators() {
147         MainUI main = getContext().getMainUI();
148         Preconditions.checkNotNull(
149                 main, "No mainUI registred in application context");
150         MainUIHandler handler = main.getHandler();
151         handler.clearValidators();
152     }
153 
154     public String getWeightStringValue(JComponent component, Float weight) {
155 
156 
157         WeightUnit weightUnit = (WeightUnit) component.getClientProperty("addWeightUnit");
158         Objects.requireNonNull(weightUnit, "can't find addWeightUnit client property on component: " + component);
159         return weightUnit.renderWeight(weight);
160     }
161 
162 
163     @Override
164     public <O> Decorator<O> getDecorator(Class<O> type, String name) {
165         DecoratorService decoratorService =
166                 getContext().getDecoratorService();
167 
168         Preconditions.checkNotNull(type);
169 
170         Decorator decorator = decoratorService.getDecoratorByType(type, name);
171         if (decorator == null) {
172 
173             if (LabelAware.class.isAssignableFrom(type)) {
174                 decorator = getDecorator(LabelAware.class, null);
175             }
176         }
177         Preconditions.checkNotNull(decorator);
178         return decorator;
179     }
180 
181     @Override
182     protected void addHighlighters(final JXTable table) {
183 
184         HighlightPredicate notSelectedPredicate = new HighlightPredicate.NotHighlightPredicate(HighlightPredicate.IS_SELECTED);
185         HighlightPredicate rowIsInvalidPredicate = (renderer, adapter) -> {
186 
187             boolean result = false;
188             if (adapter.isEditable()) {
189                 AbstractApplicationTableModel model = (AbstractApplicationTableModel) table.getModel();
190                 int viewRow = adapter.row;
191                 int modelRow = adapter.convertRowIndexToModel(viewRow);
192                 AbstractTuttiBeanUIModel row = (AbstractTuttiBeanUIModel) model.getEntry(modelRow);
193                 result = !row.isValid();
194             }
195             return result;
196         };
197         HighlightPredicate rowIsValidPredicate =
198                 new HighlightPredicate.NotHighlightPredicate(rowIsInvalidPredicate);
199         Highlighter selectedHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
200                 HighlightPredicate.IS_SELECTED,
201                 getConfig().getColorSelectedRow());
202         table.addHighlighter(selectedHighlighter);
203 
204         // paint in a special color for read only cells (not selected)
205         Highlighter readOnlyHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
206                 new HighlightPredicate.AndHighlightPredicate(
207                         HighlightPredicate.READ_ONLY,
208                         notSelectedPredicate),
209                 getConfig().getColorRowReadOnly());
210         table.addHighlighter(readOnlyHighlighter);
211 
212         // paint in a special color for read only cells (selected)
213         Highlighter readOnlySelectedHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
214                 new HighlightPredicate.AndHighlightPredicate(
215                         HighlightPredicate.READ_ONLY,
216                         HighlightPredicate.IS_SELECTED),
217                 getConfig().getColorRowReadOnly().darker());
218         table.addHighlighter(readOnlySelectedHighlighter);
219 
220         // paint in a special color inValid rows (not selected)
221         Highlighter validHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
222                 new HighlightPredicate.AndHighlightPredicate(
223                         HighlightPredicate.EDITABLE,
224                         notSelectedPredicate,
225                         rowIsInvalidPredicate),
226                 getConfig().getColorRowInvalid());
227         table.addHighlighter(validHighlighter);
228 
229         // paint in a special color inValid rows (selected)
230         Highlighter validSelectedHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
231                 new HighlightPredicate.AndHighlightPredicate(
232                         HighlightPredicate.EDITABLE,
233                         HighlightPredicate.IS_SELECTED,
234                         rowIsInvalidPredicate),
235                 getConfig().getColorRowInvalid().darker());
236         table.addHighlighter(validSelectedHighlighter);
237 
238         // use configured color odd row (not for selected)
239         Highlighter evenHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
240                 new HighlightPredicate.AndHighlightPredicate(
241                         HighlightPredicate.ODD,
242                         notSelectedPredicate,
243                         rowIsValidPredicate,
244                         HighlightPredicate.READ_ONLY),
245                 getConfig().getColorAlternateRow().darker());
246         table.addHighlighter(evenHighlighter);
247 
248         Highlighter evenNotReadOnlyHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
249                 new HighlightPredicate.AndHighlightPredicate(
250                         HighlightPredicate.ODD,
251                         notSelectedPredicate,
252                         rowIsValidPredicate,
253                         HighlightPredicate.EDITABLE),
254                 getConfig().getColorAlternateRow());
255         table.addHighlighter(evenNotReadOnlyHighlighter);
256 
257         // use configured color odd row (for selected)
258         Highlighter evenSelectedHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
259                 new HighlightPredicate.AndHighlightPredicate(
260                         HighlightPredicate.ODD,
261                         HighlightPredicate.IS_SELECTED,
262                         rowIsValidPredicate,
263                         HighlightPredicate.EDITABLE),
264                 getConfig().getColorSelectedRow());
265         table.addHighlighter(evenSelectedHighlighter);
266 
267 
268         // paint in a special color inValid rows
269         Font font = table.getFont().deriveFont(Font.BOLD);
270         Highlighter selectHighlighter = new FontHighlighter(HighlightPredicate.IS_SELECTED, font);
271         table.addHighlighter(selectHighlighter);
272     }
273 
274     protected void listenModelModifiy(AbstractTuttiBeanUIModel model) {
275         model.addPropertyChangeListener(AbstractTuttiBeanUIModel.PROPERTY_MODIFY, evt -> {
276             Boolean modify = (Boolean) evt.getNewValue();
277             if (modify != null && modify) {
278                 ((AbstractTuttiBeanUIModel) getModel()).setModify(true);
279             }
280         });
281     }
282 
283     //------------------------------------------------------------------------//
284     //-- Init methods                                                       --//
285     //------------------------------------------------------------------------//
286 
287     @Override
288     protected void initUIComponent(Object component) {
289         if (component instanceof NumberEditor) {
290             initNumberEditor((NumberEditor) component);
291         } else if (component instanceof JXTitledPanel) {
292             initJXTitledPanel((JXTitledPanel) component);
293         } else if (component instanceof ButtonAttachment) {
294 
295             initButtonAttachment((ButtonAttachment) component);
296         } else if (component instanceof JComboBox) {
297 
298             initComboBox((JComboBox) component);
299         } else {
300             super.initUIComponent(component);
301         }
302     }
303 
304     private void initComboBox(JComboBox<?> comboBox) {
305 
306         super.initUIComponent(comboBox);
307         List<JButton> comboboxActions = (List<JButton>) comboBox.getClientProperty("comboboxActions");
308         if (comboboxActions != null) {
309 
310             comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
311             comboBox.addMouseListener(TuttiUIUtil.GRAB_FOCUS_ON_ENTER_LISTENER);
312 
313             comboBox.setRenderer(new ActionListCellRenderer());
314             comboBox.setModel(new DefaultComboBoxModel(comboboxActions.toArray()));
315             comboBox.addPropertyChangeListener("enabled", evt -> {
316                 JComboBox source = (JComboBox) evt.getSource();
317                 source.setFocusable((Boolean) evt.getNewValue());
318             });
319             comboBox.addMouseListener(new MouseAdapter() {
320                 @Override
321                 public void mouseEntered(MouseEvent e) {
322 
323                     JComboBox source = (JComboBox) e.getSource();
324 
325                     if (source.isEnabled()) {
326 
327                         ShowComboBoxPopupActions task = new ShowComboBoxPopupActions(source);
328 
329                         try {
330                             getContext().getTimer().schedule(task, 300);
331                         } catch (IllegalStateException e1) {
332                             getContext().reloadTimer().schedule(task, 300);
333                         }
334 
335                     }
336 
337                 }
338 
339                 @Override
340                 public void mouseClicked(MouseEvent e) {
341 
342                     JComboBox source = (JComboBox) e.getSource();
343                     if (source.isEnabled()) {
344 
345                         AbstractButton action = (AbstractButton) source.getItemAt(0);
346                         getContext().getActionEngine().runAction(action);
347 
348                     }
349 
350                 }
351             });
352 
353             comboBox.addActionListener(e -> {
354 
355                 JComboBox source = (JComboBox) e.getSource();
356                 Boolean canEdit = (Boolean) source.getClientProperty(CAN_EDIT);
357                 if (canEdit == null || canEdit) {
358 
359                     JButton selectedAction = (JButton) source.getSelectedItem();
360                     // hide popup before performing the action, otherwise, if the action
361                     // opens a popup, the user must click a first time to hide the combobox
362                     // popup to then interact with the popup opened by the action
363                     // (see http://forge.codelutin.com/issues/2032)
364                     source.setSelectedIndex(0);
365                     source.hidePopup();
366                     getContext().getActionEngine().runAction(selectedAction);
367 
368                 }
369             });
370         }
371     }
372 
373     public void resetComboBoxAction(JComboBox source) {
374         source.putClientProperty(CAN_EDIT, false);
375 
376         try {
377             source.setSelectedIndex(0);
378         } finally {
379             source.putClientProperty(CAN_EDIT, null);
380         }
381     }
382 
383     protected void initJXTitledPanel(JXTitledPanel jTextField) {
384 //        Boolean boldFont = (Boolean) jTextField.getClientProperty("boldFont");
385 //        if (boldFont!= null && boldFont) {
386 //            Font font = jTextField.getFont().deriveFont(Font.BOLD, 13.f);
387 //            jTextField.setTitleFont(font);
388 //        }
389     }
390 
391     @Override
392     protected void initTextField(JTextField jTextField) {
393         super.initTextField(jTextField);
394         Boolean computed = (Boolean) jTextField.getClientProperty("computed");
395         if (computed != null && computed) {
396             Font font = jTextField.getFont().deriveFont(Font.ITALIC);
397             jTextField.setFont(font);
398             jTextField.setEditable(false);
399             jTextField.setEnabled(false);
400             jTextField.setDisabledTextColor(getConfig().getColorComputedWeights());
401         }
402     }
403 
404     protected void initButtonAttachment(ButtonAttachment component) {
405 
406         component.init();
407     }
408 
409     @Override
410     protected void initLabel(JLabel jLabel) {
411 
412         WeightUnit weightUnit = (WeightUnit) jLabel.getClientProperty("addWeightUnit");
413         if (weightUnit != null) {
414             String text = weightUnit.decorateLabel(jLabel.getText());
415             jLabel.setText(text);
416 
417             String tip = weightUnit.decorateTip(jLabel.getToolTipText());
418             jLabel.setToolTipText(tip);
419 
420             Component labelFor = jLabel.getLabelFor();
421             if (labelFor instanceof ComputableDataEditor) {
422 
423                 // set also the number of digits (4 for kg, 1 for g)
424                 ComputableDataEditor editor = (ComputableDataEditor) labelFor;
425                 editor.setWeightUnit(weightUnit);
426             } else if (labelFor instanceof NumberEditor) {
427 
428                 // set also the number of digits (4 for kg, 1 for g)
429                 NumberEditor editor = (NumberEditor) labelFor;
430                 editor.setNumberPattern(weightUnit.getNumberEditorPattern());
431             }
432         }
433     }
434 
435     @Override
436     protected void initButton(AbstractButton abstractButton) {
437 
438         super.initButton(abstractButton);
439 
440         TuttiUIUtil.initButton(getContext(), this.getUI(), abstractButton);
441 
442     }
443 
444     protected void initNumberEditor(NumberEditor editor) {
445         if (log.isDebugEnabled()) {
446             log.debug("init number editor " + editor.getName());
447         }
448         editor.init();
449 
450         // Force binding if value is already in model
451         Number model = editor.getModel().getNumberValue();
452         if (model != null) {
453             editor.setNumberValue(null);
454             editor.setNumberValue(model);
455         }
456 
457         if (isAutoSelectOnFocus(editor)) {
458 
459             addAutoSelectOnFocus(editor.getTextField());
460         }
461     }
462 
463 
464     public String buildReminderLabelTitle(Species species,
465                                           Iterable<SampleCategory<?>> categories,
466                                           String prefix,
467                                           String suffix) {
468         return buildReminderLabelTitle(species, categories, prefix, suffix, true);
469 
470     }
471 
472     public String buildReminderLabelTitle(Species species,
473                                           Iterable<SampleCategory<?>> categories,
474                                           String prefix,
475                                           String suffix,
476                                           boolean html) {
477         return buildReminderLabelTitle(
478                 decorate(species, DecoratorService.WITH_SURVEY_CODE),
479                 categories,
480                 prefix,
481                 suffix,
482                 html);
483 
484     }
485 
486     //------------------------------------------------------------------------//
487     //-- Internal methods                                                   --//
488     //------------------------------------------------------------------------//
489 
490     protected void registerValidators(SwingValidator... validators) {
491         MainUI main = getContext().getMainUI();
492         Preconditions.checkNotNull(
493                 main, "No mainUI registred in application context");
494         MainUIHandler handler = main.getHandler();
495         handler.clearValidators();
496         for (SwingValidator validator : validators) {
497             handler.registerValidator(validator);
498         }
499     }
500 
501     protected void listenValidatorValid(SimpleBeanValidator validator,
502                                         final AbstractTuttiBeanUIModel model) {
503         validator.addPropertyChangeListener(SimpleBeanValidator.VALID_PROPERTY, evt -> {
504             if (log.isDebugEnabled()) {
505                 log.debug("Model [" + model +
506                           "] pass to valid state [" +
507                           evt.getNewValue() + "]");
508             }
509             model.setValid((Boolean) evt.getNewValue());
510         });
511     }
512 
513     protected void listenValidationTableHasNoFatalError(final SimpleBeanValidator validator,
514                                                         final AbstractTuttiBeanUIModel model) {
515         getContext().getMainUI().getValidatorMessageWidget().addTableModelListener(e -> {
516             boolean valid = !validator.hasFatalErrors();
517             if (log.isDebugEnabled()) {
518                 log.debug("Model [" + model +
519                           "] pass to valid state [" + valid + "]");
520             }
521             model.setValid(valid);
522         });
523     }
524 
525     protected void listModelIsModify(AbstractTuttiBeanUIModel model) {
526         model.addPropertyChangeListener(new PropertyChangeListener() {
527 
528             final Set<String> excludeProperties = getPropertiesToIgnore();
529 
530             @Override
531             public void propertyChange(PropertyChangeEvent evt) {
532                 if (!excludeProperties.contains(evt.getPropertyName())) {
533                     ((AbstractTuttiBeanUIModel) evt.getSource()).setModify(true);
534                 }
535             }
536         });
537     }
538 
539     protected Set<String> getPropertiesToIgnore() {
540         return Sets.newHashSet(
541                 AbstractTuttiBeanUIModel.PROPERTY_MODIFY,
542                 AbstractTuttiBeanUIModel.PROPERTY_VALID);
543     }
544 
545     protected void closeUI(TuttiUI ui) {
546         ui.getHandler().onCloseUI();
547     }
548 
549     protected String buildReminderLabelTitle(String species,
550                                              Iterable<SampleCategory<?>> categories,
551                                              String prefix,
552                                              String suffix) {
553         return buildReminderLabelTitle(species, categories, prefix, suffix, true);
554     }
555 
556     protected String buildReminderLabelTitle(String species,
557                                              Iterable<SampleCategory<?>> categories,
558                                              String prefix,
559                                              String suffix,
560                                              boolean html) {
561         StringBuilder title = new StringBuilder();
562         if (html) {
563             title.append("<html><body style='color:black;'>");
564         }
565         title.append(prefix).append(" - [");
566 
567         if (html) {
568             title.append("<strong>");
569         }
570         title.append(species);
571 
572         if (html) {
573             title.append("</strong>");
574         }
575         title.append("]");
576 
577         if (categories != null) {
578             for (SampleCategory<?> sampleCategory : categories) {
579                 if (sampleCategory.getCategoryValue() != null) {
580                     title.append(" - ");
581                     title.append(decorate(sampleCategory.getCategoryValue()));
582                 }
583             }
584         }
585 
586         title.append(" - ").append(suffix);
587         if (html) {
588             title.append("</body></html>");
589         }
590 
591         return title.toString();
592     }
593 
594     protected <R> TableColumnExt addFloatColumnToModel(TableColumnModel model,
595                                                        ColumnIdentifier<R> identifier,
596                                                        WeightUnit weightUnit,
597                                                        JTable table) {
598 
599         Preconditions.checkNotNull(weightUnit);
600         NumberCellEditor<Float> editor =
601                 JAXXWidgetUtil.newNumberTableCellEditor(Float.class, false);
602         editor.getNumberEditor().setSelectAllTextOnError(true);
603         editor.getNumberEditor().getTextField().setBorder(new LineBorder(Color.GRAY, 2));
604         editor.getNumberEditor().setNumberPattern(weightUnit.getNumberEditorPattern());
605 
606         TableCellRenderer renderer = newWeightCellRenderer(table.getDefaultRenderer(Number.class), weightUnit);
607 
608         return addColumnToModel(model, editor, renderer, identifier, weightUnit);
609     }
610 
611     protected <R> TableColumnExt addColumnToModel(TableColumnModel model,
612                                                   TableCellEditor editor,
613                                                   TableCellRenderer renderer,
614                                                   ColumnIdentifier<R> identifier,
615                                                   WeightUnit weightUnit) {
616 
617         TableColumnExt col = new TableColumnExt(model.getColumnCount());
618         col.setCellEditor(editor);
619         col.setCellRenderer(renderer);
620         String label = t(identifier.getHeaderI18nKey());
621         if (weightUnit != null) {
622             label = weightUnit.decorateLabel(label);
623         }
624         col.setHeaderValue(label);
625         String tip = t(identifier.getHeaderTipI18nKey());
626         if (weightUnit != null) {
627             tip = weightUnit.decorateTip(tip);
628         }
629         col.setToolTipText(tip);
630 
631         col.setIdentifier(identifier);
632         model.addColumn(col);
633         // by default no column is sortable, must specify it
634         col.setSortable(false);
635         return col;
636     }
637 
638     protected TableCellRenderer newWeightCellRenderer( TableCellRenderer delegate, WeightUnit weightUnit) {
639         return (table, value, isSelected, hasFocus, row, column) -> {
640             Component result = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
641             if(result instanceof JLabel) {
642                 JLabel jLabel = (JLabel)result;
643                 jLabel.setHorizontalTextPosition(4);
644                 jLabel.setText(weightUnit.renderWeight((Float) value));
645             }
646 
647             return result;
648         };
649     }
650 }