Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.mateu.mdd.vaadin.components.views.EditorViewComponent Maven / Gradle / Ivy
package io.mateu.mdd.vaadin.components.views;
import com.google.common.base.Strings;
import com.vaadin.data.Binder;
import com.vaadin.data.BinderValidationStatus;
import com.vaadin.data.HasValue;
import com.vaadin.data.Validator;
import com.vaadin.event.ShortcutAction;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.ContentMode;
import com.vaadin.ui.Button;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.ValoTheme;
import io.mateu.mdd.core.MDD;
import io.mateu.mdd.core.app.AbstractAction;
import io.mateu.mdd.core.app.MDDRunnableAction;
import io.mateu.mdd.core.interfaces.*;
import io.mateu.mdd.core.interfaces.ReadOnly;
import io.mateu.mdd.core.ui.MDDUIAccessor;
import io.mateu.mdd.shared.CSS;
import io.mateu.mdd.shared.FormLayoutBuilderParameters;
import io.mateu.mdd.shared.annotations.*;
import io.mateu.mdd.shared.data.Status;
import io.mateu.mdd.shared.interfaces.HasStatus;
import io.mateu.mdd.shared.interfaces.IResource;
import io.mateu.mdd.shared.reflection.FieldInterfaced;
import io.mateu.mdd.vaadin.MateuUI;
import io.mateu.mdd.vaadin.components.ClassOption;
import io.mateu.mdd.vaadin.components.app.views.secondLevel.FiltersViewFlowComponent;
import io.mateu.mdd.vaadin.data.MDDBinder;
import io.mateu.mdd.vaadin.util.BindedWindow;
import io.mateu.mdd.vaadin.util.VaadinHelper;
import io.mateu.reflection.ReflectionHelper;
import io.mateu.reflection.Transferrer;
import io.mateu.util.data.Pair;
import io.mateu.util.interfaces.EditorViewStyler;
import io.mateu.util.notification.Notifier;
import io.mateu.util.persistence.JPAHelper;
import io.mateu.util.persistence.JPATransaction;
import io.mateu.util.servlet.common.HasChangesSignature;
import lombok.extern.slf4j.Slf4j;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.OptimisticLockException;
import javax.validation.constraints.NotNull;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
@Slf4j
public class EditorViewComponent extends AbstractViewComponent implements IEditorViewComponent {
private boolean createSaveButton;
private final List visibleFields;
private final List hiddenFields;
private ListViewComponent listViewComponent;
private Object owner = null;
private FieldInterfaced field = null;
private Map> validators = new HashMap<>();
List componentsToLookForErrors = new ArrayList<>();
private Map embeddedListViewComponents = new HashMap<>();
protected boolean newRecord;
private Class modelType;
private MDDBinder binder;
private AbstractStylist stylist;
private Panel panel;
private Layout kpisContainer;
private Layout kpis;
private Panel panelContenido;
private List listeners = new ArrayList<>();
private List shortcutsCreated = new ArrayList<>();
private Object modelId;
private Map> mvs = new HashMap<>();
private Object parent;
private Map initialValues;
private CssLayout links;
private Map> actionsPerSection = new HashMap<>();
private VerticalLayout actionsContainer;
private String focusedSectionId;
private Map> actionsPerField = new HashMap<>();
private BindedWindow creatorWindow;
private Runnable beforeOpen;
private TabSheet sectionTabSheet;
private Component selectedTab;
public String _defaultAction;
private Label statusLabel;
private boolean firstBuild = true;
public Map getInitialValues() {
return initialValues;
}
public void setInitialValues(Map initialValues) {
this.initialValues = initialValues;
}
public Map> getActionsPerSection() {
return actionsPerSection;
}
public Map getEmbeddedListViewComponents() {
return embeddedListViewComponents;
}
public Runnable getBeforeOpen() {
return beforeOpen;
}
public void setBeforeOpen(Runnable beforeOpen) {
this.beforeOpen = beforeOpen;
}
public BindedWindow getCreatorWindow() {
return creatorWindow;
}
public String getFocusedSectionId() {
return focusedSectionId;
}
public void setFocusedSectionId(String focusedSectionId) {
this.focusedSectionId = focusedSectionId;
}
public void setFocusedSection(TabSheet sectionTabSheet, Component selectedTab) {
this.sectionTabSheet = sectionTabSheet;
this.selectedTab = selectedTab;
setFocusedSectionId("" + selectedTab.getId());
}
public void setCreateSaveButton(boolean createSaveButton) {
this.createSaveButton = createSaveButton;
}
public boolean isCreateSaveButton() {
return createSaveButton;
}
@Override
public VaadinIcons getIcon() {
return super.getIcon() != null?super.getIcon():VaadinIcons.EDIT;
}
public void setKpisContainer(Layout kpisContainer) {
this.kpisContainer = kpisContainer;
if (kpis != null) kpisContainer.addComponent(kpis);
}
@Override
public void setParentView(AbstractViewComponent parentView) {
super.setParentView(parentView);
if (parentView instanceof ListViewComponent) setListViewComponent((ListViewComponent) parentView);
}
public ListViewComponent getListViewComponent() {
return listViewComponent;
}
public void setListViewComponent(ListViewComponent listViewComponent) {
this.listViewComponent = listViewComponent;
}
public boolean isModificado() {
return isModificado(initialValues, buildSignature());
}
public static boolean isModificado(Map initialValues, Map currentValues) {
boolean modificado = false;
if (initialValues != null) {
for (String k : initialValues.keySet()) {
Object v0 = initialValues.get(k);
Object v = currentValues.get(k);
if (
!(v0 != null && v0 instanceof String && "".equals(v0) && v == null)
&& !(v != null && v instanceof String && "".equals(v) && v0 == null)
&& ((v0 == null && v != null) || (v0 != null && !v0.equals(v)))
) {
log.debug("modificado. k=" + k + ",v0=" + v0 + ",v=" + v);
modificado = true;
break;
}
}
}
return modificado;
}
public boolean isNewRecord() {
return newRecord;
}
public void setModelType(Class modelType) {
this.modelType = modelType;
}
public void addEditorListener(EditorListener listener) {
listeners.add(listener);
}
public MDDBinder getBinder() {
return binder;
}
public EditorViewComponent(Class modelType) {
this(modelType, true);
}
public EditorViewComponent(ListViewComponent listViewComponent, Class modelType) {
this(listViewComponent, modelType, true);
}
public EditorViewComponent(ListViewComponent listViewComponent, Object owner, FieldInterfaced field, Class modelType, List visibleFields, List hiddenFields, boolean createSaveButton) {
this.listViewComponent = listViewComponent;
this.owner = owner;
this.field = field;
this.modelType = modelType;
if (false && modelType.isAnnotationPresent(Entity.class)) {
try {
this.modelType = getPojoTypeForEntity(modelType);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
this.visibleFields = visibleFields;
this.hiddenFields = hiddenFields;
this.createSaveButton = createSaveButton;
}
private Class getPojoTypeForEntity(Class modelType) throws ClassNotFoundException {
return Class.forName(modelType.getName() + "Pojo");
}
public EditorViewComponent(Object owner, FieldInterfaced field, Class modelType, boolean createSaveButton) {
this(null, owner, field, modelType, new ArrayList<>(), new ArrayList<>(), createSaveButton);
}
public EditorViewComponent(Class modelType, boolean createSaveButton) {
this(null, null, modelType, createSaveButton);
}
public EditorViewComponent(ListViewComponent listViewComponent, Class modelType, boolean createSaveButton) {
this(listViewComponent, null, null, modelType, new ArrayList<>(), new ArrayList<>(), createSaveButton);
}
public EditorViewComponent(ListViewComponent listViewComponent, Class modelType, boolean createSaveButton, List visibleFields) {
this(listViewComponent, null, null, modelType, visibleFields, new ArrayList<>(), createSaveButton);
}
public EditorViewComponent(Object model) {
this(model, true);
}
public EditorViewComponent(Object model, Component lastViewComponent) {
this(lastViewComponent instanceof ListViewComponent? (ListViewComponent) lastViewComponent :null, model, null, null, true);
}
public EditorViewComponent(Object model, List visibleFields, List hiddenFields) {
this(model, visibleFields, hiddenFields, true);
}
public EditorViewComponent(ListViewComponent listViewComponent, Object model, List visibleFields, List hiddenFields) {
this(listViewComponent, model, visibleFields, hiddenFields, true);
}
public EditorViewComponent(Object model, boolean createSaveButton) {
this(model, new ArrayList<>(), new ArrayList<>(), createSaveButton);
}
public EditorViewComponent(Object model, List visibleFields, List hiddenFields, boolean createSaveButton) {
this(null, model, visibleFields, hiddenFields, createSaveButton);
}
public EditorViewComponent(ListViewComponent listViewComponent, Object model, List visibleFields, List hiddenFields, boolean createSaveButton) {
this.listViewComponent = listViewComponent;
this.modelType = model.getClass();
this.visibleFields = visibleFields;
this.hiddenFields = hiddenFields;
this.createSaveButton = !(this instanceof OwnedCollectionViewComponent) && createSaveButton;
setModel(model);
}
public Object getModel() {
return (binder != null)?binder.getBean():null;
}
public void setModel(Object model) {
setModel(model, true);
}
public void setModel(Object model, boolean updateChangesSignature) {
if (model != null) {
modelType = model.getClass();
} else {
try {
model = modelType.newInstance();
} catch (Exception e) {
Notifier.alert(e);
}
}
Object old = getModel();
if (old != null) listeners.remove(old);
if (model instanceof EditorListener) addEditorListener((EditorListener) model);
binder = new MDDBinder(model.getClass(), this);
if (model != null) {
if (model.getClass().isAnnotationPresent(Entity.class)) {
modelId = ReflectionHelper.getId(model);
} else if (PersistentPojo.class.isAssignableFrom(model.getClass())) {
modelId = ((PersistentPojo) model).getId();
} else {
modelId = model.toString();
}
}
binder.addValueChangeListener((HasValue.ValueChangeListener) valueChangeEvent -> {
updateStatus(valueChangeEvent.getValue());
});
binder.setBean(model);
updateStatus(model);
String oldFocusedSectionId = focusedSectionId;
build(model);
if (!Strings.isNullOrEmpty(oldFocusedSectionId) && sectionTabSheet != null) {
sectionTabSheet.setSelectedTab(Integer.parseInt(oldFocusedSectionId));
focusedSectionId = oldFocusedSectionId;
}
rebuildActions();
if (updateChangesSignature) initialValues = buildSignature();
}
private void updateStatus(Object model) {
if (statusLabel == null) buildStatusBar();
if (model == null) {
applyStatus(null);
} else {
try {
Status s = null;
if (model instanceof HasStatus) {
s = ((HasStatus) model).getStatus();
}
applyStatus(s);
} catch (Exception e) {
statusLabel.setValue("" + e.getClass().getSimpleName() + ": " + e.getMessage());
}
}
}
private void applyStatus(Status s) {
if (statusLabel != null) {
statusLabel.setValue(getSquareSvg() + " "+ (s == null ? "---" : s.getMessage()));
statusLabel.removeStyleNames("NONE", "INFO", "SUCCESS", "WARNING", "DANGER");
statusLabel.addStyleName(s.getType().toString());
}
}
private String getSquareSvg() {
return " ";
}
private String getCircleSvg() {
return " ";
}
public Map buildSignature() {
return buildSignature(getModel());
}
public static Map buildSignature(Object m) {
Map s = new HashMap<>();
if (m != null && m instanceof HasChangesSignature) {
s.put("signature", ((HasChangesSignature) m).getChangesSignature());
} else if (m != null) {
List seen = new ArrayList<>();
seen.add(m);
for (FieldInterfaced f : ReflectionHelper.getAllEditableFields(m.getClass())) if (!Modifier.isTransient(f.getModifiers())) {
try {
Object v = ReflectionHelper.getValue(f, m);
if (v != null) {
if (v instanceof Collection) {
Collection col = (Collection) v;
String cols = "";
for (Object o : col) {
if (!"".equals(cols)) cols += ",";
cols += "" + serialize(seen, o);
}
s.put(f.getName(), cols);
continue;
}
} else v = "";
s.put(f.getName(), "" + v);
} catch (Exception e) {
s.put(f.getName(), null);
}
}
}
return s;
}
public static String serialize(List seen, Object o) {
String s = "";
if (o != null) {
if (seen.contains(o)) return "" + o;
seen.add(o);
for (FieldInterfaced f : ReflectionHelper.getAllEditableFields(o.getClass())) {
if (!"".equals(s)) s += "&";
try {
s += f.getName() + "=";
Object v = ReflectionHelper.getValue(f, o);
if (v != null) {
if (v instanceof Collection) {
String z = "";
for (Object i : (Collection) v) {
if (!"".equals(z)) z += "|";
z += serialize(seen, i);
}
v = z;
} else if (v instanceof Map) {
String z = "";
for (Object i : ((Map) v).keySet()) {
if (!"".equals(z)) z += "|";
z += serialize(seen, i) + "->" + serialize(seen, ((Map) v).get(i));
}
v = z;
}
} else v = "";
s += v;
} catch (Exception e) {
s += f.getName() + "=exception";
}
}
} else s = "null";
return s;
}
private void build(Object model) {
if (isResource(model)) {
model = new ResourceModel((IResource) model);
}
long t0 = System.currentTimeMillis();
if (model != null && model.getClass().isAnnotationPresent(Entity.class)) {
Object id = ReflectionHelper.getId(model);
boolean esNuevo = false;
if (id instanceof Long) {
esNuevo = ((Long) id) == 0;
} else if (id instanceof Integer) {
esNuevo = ((Integer)id) == 0;
} else {
esNuevo = id == null;
}
newRecord = esNuevo;
}
clear();
componentsToLookForErrors = new ArrayList<>();
//MDDUI.get().getNavegador().getViewProvider().setCurrentEditor(this);
try {
if (panel == null) build();
if (links != null) links.removeAllComponents();
getActions();
updateSubheader(model);
panelContenido = new Panel();
panelContenido.addStyleName(ValoTheme.PANEL_BORDERLESS);
panelContenido.addStyleName(CSS.NOPADDING);
panelContenido.addStyleName("panelContenido");
panelContenido.setSizeFull();
if (kpis == null) {
kpis = new CssLayout();
kpis.addStyleName(CSS.NOPADDING);
}
if (kpisContainer != null) {
kpisContainer.removeAllComponents();
kpisContainer.addComponent(kpis);
}
if (!(this instanceof FiltersViewFlowComponent)) {
List kpiFields = ReflectionHelper.getKpiFields(model.getClass());
if (kpiFields.size() > 0) {
if (kpis != null) {
kpis.removeAllComponents();
for (FieldInterfaced kpi : kpiFields) {
kpis.addComponent(createKpi(binder, kpi));
}
}
}
}
panel.setContent(panelContenido);
List fields = ReflectionHelper.getAllEditableFields(model.getClass(), (owner != null) ? owner.getClass() : null, false, field);
removeUneditableFields(fields);
if (visibleFields != null && visibleFields.size() > 0) {
fields.removeIf(f -> !visibleFields.contains(f));
}
if (hiddenFields != null && hiddenFields.size() > 0) {
fields.removeIf(f -> hiddenFields.contains(f));
}
FormLayoutBuilderParameters.FormLayoutBuilderParametersBuilder params = FormLayoutBuilderParameters.builder().validators(validators).allFields(fields).links(links).actionsPerSection(actionsPerSection);
if (this instanceof FiltersViewFlowComponent) params = params.forSearchFilters(true).forSearchFiltersExtended(true).createSections(false).createTabs(false);
Pair r = FormLayoutBuilder.get().build(this, binder, model.getClass(), model, componentsToLookForErrors, params.build(), actionsPerField);
stylist = r.getValue();
panelContenido.setContent(r.getKey());
AbstractStylist finalStylist = stylist;
/*
binder.addValueChangeListener(e -> {
MDDUI.get().access(new Runnable() {
@Override
public void run() {
//rebuildActions();
binder.setBean(binder.getBean(), false); // para campos calculados
}
});
});
*/
if (getView() != null) getView().updateViewTitle(getTitle(), getSubtitle());
if (links != null) {
if (links.getComponentCount() == 0) links.setVisible(false);
else links.setVisible(true);
}
if (firstBuild && (!(model instanceof ReadOnlyPojo) || model instanceof PersistentPojo)) focusFirstField(panelContenido.getContent());
firstBuild = false;
} catch (Exception e) {
Notifier.alert(e);
}
rebuildActions();
actionsByMethod.keySet().forEach(x -> {
List as = new ArrayList<>();
Method m = (Method) x;
if (m.isAnnotationPresent(DependsOn.class)) as.add(m.getAnnotation(DependsOn.class));
Method mv = ReflectionHelper.getMethod(modelType, ReflectionHelper.getGetter(m.getName()).replaceFirst("get", "is") + "Visible");
if (mv != null && mv.isAnnotationPresent(DependsOn.class)) as.add(mv.getAnnotation(DependsOn.class));
for (DependsOn a : as) {
for (String fn : a.value().split(",")) {
fn = fn.trim();
String finalFn = fn;
Optional b = binder.getBinding(fn);
if (b.isPresent()) {
((Binder.Binding)b.get()).getField().addValueChangeListener(e -> {
//((AbstractAction)actionsByMethod.get(m)).run(new AbstractMDDExecutionContext());
rebuildActions();
});
} else {
binder.forField(new AbstractField() {
Object v = null;
@Override
protected void doSetValue(Object o) {
v = o;
}
@Override
public Object getValue() {
return v;
}
}).bind(finalFn);
}
}
}
});
if (esForm()) {
addStyleName("contenido");
addStyleName("container");
}
log.debug("editor component built in " + (System.currentTimeMillis() - t0) + " ms.");
}
private void updateSubheader(Object model) {
if (subheader != null) {
subheader.removeAllComponents();
if (model != null && model instanceof HasHeader) {
Component h = createSubheader(((HasHeader) model).getHeader());
if (h != null) {
subheader.addComponent(h);
subheader.setVisible(true);
} else {
subheader.setVisible(false);
}
}
}
}
private Component createSubheader(Header header) {
if (header == null) return null;
Label l = new Label(header.getMessage());
l.addStyleName("subheader");
String s = null;
switch (header.getType()) {
case Info: s = "v-label-info"; break;
case Success: s = ValoTheme.LABEL_SUCCESS; break;
case Warning: s = "v-label-warning"; break;
case Error: s = ValoTheme.LABEL_FAILURE; break;
}
l.addStyleName(s);
return l;
}
private boolean isResource(Object model) {
boolean r = false;
if (model instanceof IResource) r = true;
else if (model instanceof List && IResource.class.equals(ReflectionHelper.getGenericClass(model.getClass()))) r = true;
return r;
}
protected void removeUneditableFields(List fields) {
fields.stream().filter(f -> ReflectionHelper.hasGetter(f)).collect(Collectors.toList());
}
private boolean focusFirstField(Component c) {
if (c instanceof AbstractField) {
if (c instanceof TextField) ((TextField)c).selectAll();
((AbstractField) c).focus();
return true;
} else if (c instanceof ComboBox) {
((ComboBox) c).focus();
return true;
} else if (c instanceof HasComponents) {
HasComponents l = (HasComponents) c;
for (Component ch : l) {
if (focusFirstField(ch)) {
return true;
}
}
}
return false;
}
private Component createKpi(MDDBinder binder, FieldInterfaced kpi) {
VerticalLayout vl = new VerticalLayout();
vl.addStyleName("kpi");
vl.setWidthUndefined();
vl.addComponent(new Label(ReflectionHelper.getCaption(kpi)));
Label l;
vl.addComponent(l = new Label());
l.addStyleName("valor");
l.setContentMode(ContentMode.HTML);
Binder.Binding binding = binder.forField(new HasValue() {
Object v = null;
@Override
public void setValue(Object o) {
v = o;
String s = "";
if (double.class.equals(kpi.getType()) && (kpi.isAnnotationPresent(Money.class) || kpi.isAnnotationPresent(Balance.class))) {
DecimalFormat df = new DecimalFormat("##,###,###,###,##0.00");
s = df.format(v != null?v:0);
if (kpi.isAnnotationPresent(Balance.class)) {
if (v != null && ((double)v) < 0) {
l.addStyleName("negativo");
l.removeStyleName("positivo");
} else {
l.addStyleName("positivo");
l.removeStyleName("negativo");
}
}
} else {
if (v == null) s = "";
else {
if (v instanceof Boolean) {
if ((Boolean) v && !kpi.getAnnotation(KPI.class).reversed()) {
s = VaadinIcons.CHECK.getHtml();
l.addStyleName(ValoTheme.BUTTON_FRIENDLY);
} else {
s = VaadinIcons.CLOSE.getHtml();
l.addStyleName(ValoTheme.BUTTON_DANGER);
}
l.addStyleName("centered");
} else {
s = "" + v;
}
}
}
l.setValue(s);
}
@Override
public Object getValue() {
return v;
}
@Override
public Registration addValueChangeListener(ValueChangeListener valueChangeListener) {
return null;
}
@Override
public void setRequiredIndicatorVisible(boolean b) {
}
@Override
public boolean isRequiredIndicatorVisible() {
return false;
}
@Override
public void setReadOnly(boolean b) {
}
@Override
public boolean isReadOnly() {
return EditorViewComponent.this instanceof ReadOnlyViewComponent;
}
}).bind(kpi.getName());
return vl;
}
public void updateModel(Object model) {
if (binder != null) {
binder.update(model);
updateSubheader(model);
}
}
@Override
public void updatePageTitle() {
super.updatePageTitle();
if (getModel() != null && getModel() instanceof EditorViewStyler) ((EditorViewStyler) getModel()).apply(this);
}
@Override
public String toString() {
return getTitle();
}
@Override
public String getTitle() {
String t = (stylist != null)?stylist.getViewTitle(newRecord, getModel()):"Not yet";
return t;
}
@Override
public String getSubtitle() {
String t = (stylist != null)?stylist.getViewSubtitle():"Not yet";
return t;
}
public Class getModelType() {
return modelType;
}
/*
@Override
public Layout getActionsContainer() {
return actionsContainer;
}
*/
@Override
public EditorViewComponent build() throws Exception {
actionsContainer = new VerticalLayout();
actionsContainer.addStyleName("actionscontainer");
actionsContainer.addStyleName(CSS.NOPADDING);
actionsContainer.setSizeUndefined();
super.build();
addStyleName("editorviewcomponent");
if (false) {
links = new CssLayout();
links.addStyleName(CSS.NOPADDING);
addComponent(links);
}
panel = new Panel();
panel.addStyleName(ValoTheme.PANEL_BORDERLESS);
panel.addStyleName(CSS.NOPADDING);
panel.addStyleName("panelContenedor");
addComponent(panel);
if (esForm() || (modelType.isAnnotationPresent(Entity.class) || PersistentPojo.class.isAssignableFrom(modelType)
|| (listViewComponent != null && listViewComponent instanceof RpcListViewComponent
&& ((RpcListViewComponent)listViewComponent).getRpcListView() instanceof RpcCrudView))) {
addActionsBar(false);
}
return this;
}
@Override
public void addStatusBar() {
buildStatusBar();
if (statusLabel != null && statusLabel.getParent() == null) addComponent(statusLabel);
}
public void buildStatusBar() {
if (statusLabel == null) {
if (HasStatus.class.isAssignableFrom(getModelType())) {
statusLabel = new Label("---", ContentMode.HTML);
statusLabel.addStyleName("statusLabel");
}
}
}
@Override
public NavBarComponent createNavBar() {
NavBarComponent bar = super.createNavBar();
if ((!(this instanceof FiltersViewFlowComponent) && !isNewRecord() && listViewComponent != null)) {
if (!isActionPresent("prev")) {
Button i;
bar.addComponent(i = new Button("", VaadinIcons.ARROW_UP));
//bar.addComponent(i = new Button("Prev", VaadinIcons.ARROW_UP));
i.addStyleName(ValoTheme.BUTTON_QUIET);
i.addClickListener(e -> {
try {
Object xid = listViewComponent.getPrevious(modelId);
if (xid != null) {
MDDUIAccessor.goSibling(xid);
}
} catch (Throwable throwable) {
Notifier.alert(throwable);
}
});
addMenuItem("prev", i);
i.setClickShortcut(ShortcutAction.KeyCode.ARROW_UP, ShortcutAction.ModifierKey.CTRL, ShortcutAction.ModifierKey.ALT);
shortcutsCreated.add("prev");
}
if (!isActionPresent("next")) {
Button i;
bar.addComponent(i = new Button("", VaadinIcons.ARROW_DOWN));
//bar.addComponent(i = new Button("Next", VaadinIcons.ARROW_DOWN));
i.addStyleName(ValoTheme.BUTTON_QUIET);
i.addClickListener(e -> {
try {
Object xid = listViewComponent.getNext(modelId);
if (xid != null) {
MDDUIAccessor.goSibling(xid);
}
} catch (Throwable throwable) {
Notifier.alert(throwable);
}
});
addMenuItem("next", i);
i.setClickShortcut(ShortcutAction.KeyCode.ARROW_DOWN, ShortcutAction.ModifierKey.CTRL, ShortcutAction.ModifierKey.ALT);
shortcutsCreated.add("next");
}
}
return bar;
}
@Override
public boolean esForm() {
return listViewComponent == null && (modelType.isAnnotationPresent(io.mateu.mdd.core.annotations.MateuUI.class) || !(modelType.isAnnotationPresent(Entity.class) || PersistentPojo.class.isAssignableFrom(modelType)));
}
private void updateActions() {
if (stylist != null) {
Object model = binder.getBean();
for (String k : (Set) menuItemsById.keySet()) {
Object c = menuItemsById.get(k);
if (c instanceof MenuBar.MenuItem) ((MenuBar.MenuItem)c).setEnabled(stylist.isActionEnabled(k, model));
else if (c instanceof Button) ((Button) c).setEnabled(stylist.isActionEnabled(k, model));
}
}
if (bar != null) {
if (bar.getComponentCount() == 0) bar.setVisible(false);
else bar.setVisible(true);
}
if (actions != null) {
if (actions.getComponentCount() == 0) actionsSection.setVisible(false);
else {
actions.getComponent(actions.getComponentCount() - 1).addStyleName(ValoTheme.BUTTON_PRIMARY);
actionsSection.setVisible(true);
}
}
}
public void addViewActionsMenuItems(CssLayout bar, List actions) {
boolean isEditingNewRecord = newRecord;
Object model = getModel();
boolean readOnly = !createSaveButton ||
(!(model instanceof PersistentPojo)
&& (model instanceof ReadOnlyPojo ||
(model instanceof ReadOnly
&& ((ReadOnly) model).isReadOnly())));
if (esForm()) {
} else {
if (modelType.isAnnotationPresent(Entity.class) || PersistentPojo.class.isAssignableFrom(modelType)) {
if (field == null && !(this instanceof OwnedCollectionViewComponent) && !isActionPresent("refresh")) {
Button i;
bar.addComponent(i = new Button("", VaadinIcons.REFRESH));
//bar.addComponent(i = new Button("Refresh", VaadinIcons.REFRESH));
i.addStyleName(ValoTheme.BUTTON_QUIET);
i.addStyleName("test-action-refresh");
i.addClickListener(e -> {
try {
load(modelId);
} catch (Throwable throwable) {
Notifier.alert(throwable);
}
});
addMenuItem("refresh", i);
i.setClickShortcut(ShortcutAction.KeyCode.R, ShortcutAction.ModifierKey.CTRL);
shortcutsCreated.add("refresh");
}
}
if (!readOnly && createSaveButton && (modelType.isAnnotationPresent(Entity.class) || PersistentPojo.class.isAssignableFrom(modelType)) && (isNewRecord() || !modelType.isAnnotationPresent(Unmodifiable.class))) {
if (!isActionPresent("new")) {
if (!shortcutsCreated.contains("saveandstay")) {
Button b;
getHiddens().addComponent(b = new Button());
b.addClickListener(e -> {
BinderValidationStatus v = binder.validate();
if (v.isOk()) {
try {
preSave();
save(false);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} else MDD.alert(v);
});
b.setClickShortcut(ShortcutAction.KeyCode.S, ShortcutAction.ModifierKey.CTRL, ShortcutAction.ModifierKey.ALT);
shortcutsCreated.add("saveandstay");
}
if (!shortcutsCreated.contains("new")) {
Button b;
getHiddens().addComponent(b = new Button());
b.addClickListener(e -> {
BinderValidationStatus v = binder.validate();
if (v.isOk()) {
try {
preSave();
save(false);
Object old = getBinder().getBean();
//load(null);
Object current = ReflectionHelper.newInstance(modelType, parent);
newRecord = true;
for (FieldInterfaced f : ReflectionHelper.getAllEditableFields(old.getClass())) {
if (f.isAnnotationPresent(Keep.class)) {
ReflectionHelper.setValue(f, current, ReflectionHelper.getValue(f, old));
}
}
getBinder().setBean(current, false);
MDDUIAccessor.updateTitle(getTitle());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} else MDD.alert(v);
});
b.setClickShortcut(ShortcutAction.KeyCode.N, ShortcutAction.ModifierKey.CTRL, ShortcutAction.ModifierKey.ALT);
shortcutsCreated.add("new");
}
if ((modelType.isAnnotationPresent(Entity.class) || PersistentPojo.class.isAssignableFrom(modelType)) && !modelType.isAnnotationPresent(NonDuplicable.class) && !isActionPresent("duplicate") && !isNewRecord()) {
if (!shortcutsCreated.contains("duplicate")) {
Button b;
getHiddens().addComponent(b = new Button());
b.addClickListener(e -> {
try {
BinderValidationStatus v = binder.validate();
if (v.isOk()) {
try {
preSave();
save(false);
Object old = getBinder().getBean();
//load(null);
Object current = ReflectionHelper.newInstance(modelType, parent);
newRecord = true;
for (FieldInterfaced f : ReflectionHelper.getAllEditableFields(old.getClass())) {
if (Collection.class.isAssignableFrom(f.getType())) {
//todo: clonar colecciones y mapas
} else ReflectionHelper.setValue(f, current, ReflectionHelper.getValue(f, old));
}
getBinder().setBean(current, false);
setModel(current);
modelId = null;
MDDUIAccessor.updateTitle(getTitle());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} else MDD.alert(v);
} catch (Throwable throwable) {
Notifier.alert(throwable);
}
});
b.setClickShortcut(ShortcutAction.KeyCode.D, ShortcutAction.ModifierKey.CTRL);
shortcutsCreated.add("duplicate");
}
}
}
if (modelType == null || (!modelType.isAnnotationPresent(ModifyValuesOnly.class) && !modelType.isAnnotationPresent(NewNotAllowed.class))) if (field == null || ReflectionHelper.puedeAnadir(field)) {
if (!isActionPresent("add")) {
Button i;
bar.addComponent(i = new Button("", VaadinIcons.PLUS));
i.addStyleName("test-action-add");
//bar.addComponent(i = new Button("Add", VaadinIcons.PLUS));
//i.addStyleName(ValoTheme.BUTTON_QUIET);
i.addClickListener(e -> {
try {
BinderValidationStatus v = binder.validate();
if (v.isOk()) {
try {
preSave();
save(false);
Object old = getBinder().getBean();
//load(null);
load(null);
Object current = getModel();
for (FieldInterfaced f : ReflectionHelper.getAllEditableFields(old.getClass())) {
if (f.isAnnotationPresent(Keep.class)) {
ReflectionHelper.setValue(f, current, ReflectionHelper.getValue(f, old));
}
}
getBinder().setBean(current, false);
setModel(current);
modelId = null;
MDDUIAccessor.updateTitle(getTitle());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} else MDD.alert(v);
} catch (Throwable throwable) {
Notifier.alert(throwable);
}
});
addMenuItem("add", i);
}
}
if (modelType == null || (!modelType.isAnnotationPresent(ModifyValuesOnly.class) && !modelType.isAnnotationPresent(Indelible.class))) if (field == null || ReflectionHelper.puedeBorrar(field)) {
if (!isActionPresent("remove")) {
Button i;
bar.addComponent(i = new Button("", VaadinIcons.MINUS));
//bar.addComponent(i = new Button("Remove", VaadinIcons.MINUS));
//i.addStyleName(ValoTheme.BUTTON_QUIET);
i.addStyleName("test-action-remove");
i.addClickListener(e -> {
VaadinHelper.confirm("Are you sure you want to delete this item?", () -> {
try {
Object xid = null;
try {
xid = listViewComponent.getNext(modelId);
} catch (Throwable throwable) {
try {
xid = listViewComponent.getPrevious(modelId);
} catch (Throwable throwable2) {
}
}
if (!isEditingNewRecord) {
JPAHelper.transact(em -> {
ReflectionHelper.delete(em, em.find(getModelType(), ReflectionHelper.getId(getModel())));
});
}
if (xid != null) {
MDDUIAccessor.goSibling(xid);
} else {
goBack();
}
} catch (Throwable ex) {
Notifier.alert(ex);
}
});
});
addMenuItem("remove", i);
};
}
}
if (getMenuItemById("prev") != null) getMenuItemById("prev").setVisible(!isNewRecord() && listViewComponent != null);
if (getMenuItemById("next") != null) getMenuItemById("next").setVisible(!isNewRecord() && listViewComponent != null);
if (getMenuItemById("duplicate") != null) getMenuItemById("duplicate").setVisible(!isNewRecord());
if (getMenuItemById("add") != null && (getView() == null || getView().getWindowContainer() != null || this instanceof OwnedCollectionViewComponent)) getMenuItemById("add").setVisible(false);
if (getMenuItemById("remove") != null && (getView() == null || getView().getWindowContainer() != null || this instanceof OwnedCollectionViewComponent)) getMenuItemById("remove").setVisible(false);
if (getMenuItemById("save") != null && this instanceof OwnedCollectionViewComponent) getMenuItemById("save").setVisible(false);
}
if (bar != null) super.addViewActionsMenuItems(bar, actions);
}
public AbstractStylist getStylist() {
return stylist;
}
public void setStylist(AbstractStylist stylist) {
this.stylist = stylist;
}
@Override
public List getMainActions() {
Object bean = (binder != null)?binder.getBean():null;
boolean isEditingNewRecord = MDDUIAccessor.isEditingNewRecord();
List ms = new ArrayList<>();
List mvf = new ArrayList<>();
if (Runnable.class.isAssignableFrom(modelType)) {
ArrayList l;
actionsPerSection.put("", l = new ArrayList<>());
MDDRunnableAction a;
l.add(a = new MDDRunnableAction("Submit") {
@Override
public void run() throws Throwable {
if (validate()) {
((Runnable) bean).run();
updateModel(bean);
Label h = new Label("Thanks for submitting!");
h.addStyleName(ValoTheme.LABEL_H1);
io.mateu.mdd.shared.ui.MDDUIAccessor.setPendingResult(h);
MDDUIAccessor.go("submitted");
}
}
});
a.setId("submitted");
a.setOrder(-100);
} else if (Callable.class.isAssignableFrom(modelType)) {
ArrayList l;
actionsPerSection.put("", l = new ArrayList<>());
MDDRunnableAction a;
l.add(a = new MDDRunnableAction("Submit") {
@Override
public void run() throws Throwable {
if (validate()) {
Object r = ((Callable)bean).call();
updateModel(bean);
io.mateu.mdd.shared.ui.MDDUIAccessor.setPendingResult(r);
MDDUIAccessor.go("submitted");
}
}
});
a.setId("submitted");
a.setOrder(-100);
} else if (createSaveButton && ((modelType.isAnnotationPresent(Entity.class) || PersistentPojo.class.isAssignableFrom(modelType)
|| (listViewComponent != null && listViewComponent instanceof RpcListViewComponent
&& ((RpcListViewComponent)listViewComponent).getRpcListView() instanceof RpcCrudView)))) {
ArrayList l;
actionsPerSection.put("", l = new ArrayList<>());
MDDRunnableAction a;
l.add(a = new MDDRunnableAction("Submit") {
@Override
public void run() throws Throwable {
if (validate()) {
save(false);
updateModel(bean);
Label h = new Label("Thanks for submitting!");
h.addStyleName(ValoTheme.LABEL_H1);
io.mateu.mdd.shared.ui.MDDUIAccessor.setPendingResult(h);
MDDUIAccessor.go("submitted");
}
}
});
a.setOrder(-100);
a.setId("submitted");
}
for (Method m : ReflectionHelper.getAllMethods(modelType)) {
if (!(
Modifier.isStatic(m.getModifiers())
|| (m.isAnnotationPresent(NotWhenCreating.class) && isEditingNewRecord)
|| (m.isAnnotationPresent(NotWhenEditing.class) && !isEditingNewRecord))
&& m.isAnnotationPresent(MainAction.class) && (isCreateSaveButton() || (!m.getAnnotation(MainAction.class).saveAfter() && !m.getAnnotation(MainAction.class).saveBefore()))
) {
addMethod(m, bean, ms, mvf);
}
}
ms.sort((a, b) -> (a.getAnnotation(Action.class) != null?a.getAnnotation(Action.class).order():-100) - (b.getAnnotation(Action.class) != null?b.getAnnotation(Action.class).order():-100));
mvf.sort((a, b) -> (a.getAnnotation(Action.class) != null?a.getAnnotation(Action.class).order():-100) - (b.getAnnotation(Action.class) != null?b.getAnnotation(Action.class).order():-100));
ms.forEach(m -> {
String k = "";
actionsPerSection.putIfAbsent(k, new ArrayList<>());
List l = actionsPerSection.get(k);
AbstractAction a;
l.add(a = ViewComponentHelper.createAction(m, this));
});
List r = actionsPerSection.getOrDefault("", new ArrayList<>());
if (esForm() && r.size() > 0) {
_defaultAction = r.get(0).getId();
}
return r;
}
@Override
public List getActions(String key) {
Object bean = (binder != null)?binder.getBean():null;
boolean isEditingNewRecord = MDDUIAccessor.isEditingNewRecord();
List ms = new ArrayList<>();
List mvf = new ArrayList<>();
for (Method m : ReflectionHelper.getAllMethods(modelType)) {
if (!(
Modifier.isStatic(m.getModifiers())
|| (m.isAnnotationPresent(NotWhenCreating.class) && isEditingNewRecord)
|| (m.isAnnotationPresent(NotWhenEditing.class) && !isEditingNewRecord))
&& m.isAnnotationPresent(Action.class) && (isCreateSaveButton() || (!m.getAnnotation(Action.class).saveAfter() && !m.getAnnotation(Action.class).saveBefore()))
) {
addMethod(m, bean, ms, mvf);
}
}
ms.sort((a, b) -> (a.getAnnotation(Action.class) != null?a.getAnnotation(Action.class).order():-100) - (b.getAnnotation(Action.class) != null?b.getAnnotation(Action.class).order():-100));
mvf.sort((a, b) -> (a.getAnnotation(Action.class) != null?a.getAnnotation(Action.class).order():-100) - (b.getAnnotation(Action.class) != null?b.getAnnotation(Action.class).order():-100));
ms.forEach(m -> {
Action aa = m.getAnnotation(Action.class);
String k = aa != null?aa.section():"";
actionsPerSection.putIfAbsent(k, new ArrayList<>());
List l = actionsPerSection.get(k);
AbstractAction a;
l.add(a = ViewComponentHelper.createAction(m, this));
});
actionsPerField = new HashMap<>();
mvf.forEach(m -> {
Action aa = m.getAnnotation(Action.class);
String k = aa != null?aa.attachToField():"";
actionsPerField.putIfAbsent(k, new ArrayList<>());
List l = actionsPerField.get(k);
AbstractAction a;
l.add(a = ViewComponentHelper.createAction(m, this));
});
List r = actionsPerSection.getOrDefault(key, new ArrayList<>());
if (esForm() && r.size() > 0) {
_defaultAction = r.get(0).getId();
}
return r;
}
private void addMethod(Method m, Object bean, List ms, List mvf) {
Optional omv = mvs.get(m);
if (omv == null) {
Method mv = ReflectionHelper.getMethod(modelType, ReflectionHelper.getGetter(m.getName()).replaceFirst("get", "is") + "Visible");
omv = mv != null?Optional.of(mv):Optional.empty();
mvs.put(m, omv);
}
Method mv = null;
if (omv.isPresent()) mv = omv.get();
try {
if (mv == null || bean == null || (Boolean) mv.invoke(bean)) {
(m.getAnnotation(Action.class) == null || Strings.isNullOrEmpty(m.getAnnotation(Action.class).attachToField())?ms:mvf).add(m);
}
} catch (Exception e) {
Notifier.alert(e);
}
}
public Method getMethod(String methodName) {
Method a = null;
for (Method m : ReflectionHelper.getAllMethods(getModelType())) {
if (!Modifier.isStatic(m.getModifiers()) && m.getName().equals(methodName)) {
a = m;
break;
}
}
return a;
}
public FieldInterfaced getField(String fieldName) {
FieldInterfaced a = null;
for (FieldInterfaced m : ReflectionHelper.getAllFields(getModelType())) {
if (m.getName().equals(fieldName) || (m.getName() + "_search").equals(fieldName)) {
a = m;
break;
}
}
return a;
}
public void save() throws Throwable {
save(true);
}
public void save(boolean goBack) throws Throwable {
save(goBack, true);
}
public void preSave() throws Throwable {
for (EditorListener l : listeners) l.preSave(getModel());
}
public void save(boolean goBack, boolean notify) throws Throwable {
save(goBack, notify, false);
}
public void save(boolean goBack, boolean notify, boolean copyEditableValues) throws Throwable {
if (validate()) {
try {
if (modelType.isAnnotationPresent(Entity.class)) {
Object m = getModel();
JPAHelper.transact( new JPATransaction() {
@Override
public void run(EntityManager em) throws Throwable {
ReflectionHelper.auditar(m);
Object d = transferirValores(em, m);
setModel(d);
}
}, () -> {
log.info("entramos en el callback");
if (!goBack) {
log.info("actualizamos el ui");
UI.getCurrent().access(() -> {
try {
JPAHelper.notransact(em -> {
if (modelId != null) {
binder.update(em.find(m.getClass(), modelId));
}
initialValues = buildSignature();
});
MDDUIAccessor.updateTitle(getTitle());
} catch (Throwable throwable) {
Notifier.alert(throwable);
}
});
}
});
modelId = ReflectionHelper.getId(getModel());
JPAHelper.notransact(em -> {
binder.update(em.find(m.getClass(), modelId));
initialValues = buildSignature();
});
if (goBack) goBack();
} else if (PersistentPojo.class.isAssignableFrom(modelType)) {
PersistentPojo ppojo = (PersistentPojo) getModel();
ppojo.save();
setModel(ppojo);
if (goBack) goBack();
} else if (listViewComponent != null && listViewComponent instanceof RpcListViewComponent
&& ((RpcListViewComponent)listViewComponent).getRpcListView() instanceof RpcCrudView) {
((RpcCrudView) ((RpcListViewComponent)listViewComponent).getRpcListView()).save(getModel());
}
if (notify) listeners.forEach(l -> l.onSave(getModel()));
if (!goBack && (modelType.isAnnotationPresent(Entity.class) || PersistentPojo.class.isAssignableFrom(modelType))) {
load(modelId);
}
if (getView() != null) getView().updateViewTitle(getTitle(), getSubtitle());
} catch (OptimisticLockException ole) {
VaadinHelper.confirm("Some objects have been modified by someone else. You should refresh and recover any modification you have done. Do you want to go ahead and overwrite instead?", () -> {
try {
save(goBack, notify, true);
} catch (Throwable throwable) {
Notifier.alert(throwable);
}
});
}
}
}
public boolean validate() {
return validate(false);
}
public boolean validate(boolean silent) {
boolean noerror = true;
BinderValidationStatus status = binder.validate();
if (false && status.hasErrors()) {
noerror = false;
}
for (Component c : componentsToLookForErrors) if (c.isVisible() && c.getParent().isVisible()) {
if (c instanceof AbstractComponent && ((AbstractComponent) c).getComponentError() != null) {
noerror = false;
if (c instanceof Focusable) ((Focusable) c).focus();
break;
}
}
if (!noerror && !silent) Notifier.alert("Please solve errors for all fields");
return noerror;
}
private Object transferirValores(EntityManager em, Object m) throws Throwable {
return new Transferrer().transfer(em, m);
}
public void load(Object id, Object parent, FieldInterfaced field) throws Throwable {
this.modelId = id;
this.parent = parent;
if (id == null) {
newRecord = true;
Set subClasses = ReflectionHelper.getSubclasses(modelType);
if (subClasses.size() > 1) {
Set subClassesOptions = new LinkedHashSet<>();
subClasses.forEach(c -> subClassesOptions.add(new ClassOption(c)));
VaadinHelper.choose("Please choose type", subClassesOptions, c -> {
if (c == null) MDDUIAccessor.goBack();
else {
try {
create(((ClassOption)c).get_class(), parent);
} catch (Throwable e) {
Notifier.alert(e);
}
}
}, () -> {
MDDUIAccessor.goBack();
});
} else if (subClasses.size() == 1) {
create(subClasses.iterator().next(), parent);
} else {
create(modelType, parent);
}
} else {
newRecord = false;
if (modelType.isAnnotationPresent(Entity.class)) {
JPAHelper.notransact(new JPATransaction() {
@Override
public void run(EntityManager em) throws Throwable {
setModel(em.find(modelType, id));
}
});
} else if (PersistentPojo.class.isAssignableFrom(modelType)) {
PersistentPojo ppojo = null;
if (id != null && modelType.equals(id.getClass())) ppojo = (PersistentPojo) id;
else ppojo = (PersistentPojo) modelType.newInstance();
ppojo.load(id);
if (parent != null) {
for (FieldInterfaced f : ReflectionHelper.getAllFields(ppojo.getClass())) if (f.getType().equals(parent.getClass()) && f.isAnnotationPresent(NotNull.class)) {
ReflectionHelper.setValue(f, ppojo, parent);
break;
}
}
setModel(ppojo);
} else if (ReadOnlyPojo.class.isAssignableFrom(modelType)) {
ReadOnlyPojo ppojo = null;
if (id != null && modelType.equals(id.getClass())) {
ppojo = (ReadOnlyPojo) id;
} else {
ppojo = (ReadOnlyPojo) modelType.newInstance();
ppojo.load(id);
}
if (parent != null) {
for (FieldInterfaced f : ReflectionHelper.getAllFields(ppojo.getClass())) if (f.getType().equals(parent.getClass()) && f.isAnnotationPresent(NotNull.class)) {
ReflectionHelper.setValue(f, ppojo, parent);
break;
}
}
setModel(ppojo);
} else {
if (parent != null) {
for (FieldInterfaced f : ReflectionHelper.getAllFields(id.getClass())) if (f.getType().equals(parent.getClass()) && f.isAnnotationPresent(NotNull.class)) {
ReflectionHelper.setValue(f, id, parent);
break;
}
}
setModel(id);
}
}
}
private void create(Class type, Object parent) throws Throwable {
Constructor con = parent != null?ReflectionHelper.getConstructor(type, parent.getClass()):ReflectionHelper.getConstructor(type);
if (con != null && con.getParameterCount() > 0) {
VaadinHelper.fill(this, "I need some data", con, i -> {
try {
setModel(i);
} catch (Throwable e) {
Notifier.alert(e);
}
MateuUI.closeWindow(false);
}, () -> MDDUIAccessor.goBack());
} else setModel(ReflectionHelper.newInstance(type, parent));
}
public void load(Object id) throws Throwable {
load(id, null, null);
}
public void rebuildActions() {
markAllAsUnseen();
addViewActionsMenuItems(bar, getActions(""));
addViewActionsMenuItems(actions, getMainActions());
removeUnseen();
updateActions();
}
public void clear() {
log.debug("*********CLEAR PANEL***********");
if (panel != null) panel.setContent(null);
}
public void onGoBack() {
if (binder != null) for (EditorListener l : listeners) l.onGoBack(binder.getBean());
}
public void goBack() {
MDDUIAccessor.goBack();
}
public void setCreatorWindow(BindedWindow creatorWindow) {
this.creatorWindow = creatorWindow;
}
@Override
public String getMainActionsTitle() {
String title = super.getMainActionsTitle();
if (getModelType().isAnnotationPresent(ActionsTitle.class)) {
title = ((ActionsTitle)getModelType().getAnnotation(ActionsTitle.class)).value();
}
return title;
}
@Override
public String getMainActionsText() {
String title = super.getMainActionsText();
if (getModelType().isAnnotationPresent(ActionsText.class)) {
title = ((ActionsText)getModelType().getAnnotation(ActionsText.class)).value();
}
return title;
}
}