/**
* ***************************************************************************
* Copyright (c) 2010 Qcadoo Limited
* Project: Qcadoo Framework
* Version: 1.4
*
* This file is part of Qcadoo.
*
* Qcadoo is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* ***************************************************************************
*/
package com.qcadoo.view.internal.components.lookup;
import static com.google.common.base.Preconditions.checkState;
import static org.springframework.util.StringUtils.hasText;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.google.common.collect.ImmutableMap;
import com.qcadoo.model.api.DataDefinition;
import com.qcadoo.model.api.FieldDefinition;
import com.qcadoo.model.api.types.JoinFieldHolder;
import com.qcadoo.view.api.ComponentState;
import com.qcadoo.view.api.ribbon.RibbonActionItem.Type;
import com.qcadoo.view.internal.ComponentDefinition;
import com.qcadoo.view.internal.ComponentOption;
import com.qcadoo.view.internal.CriteriaModifier;
import com.qcadoo.view.internal.ModalDimensions;
import com.qcadoo.view.internal.RowStyleResolver;
import com.qcadoo.view.internal.api.InternalViewDefinition;
import com.qcadoo.view.internal.api.InternalViewDefinitionService;
import com.qcadoo.view.internal.api.ViewDefinition;
import com.qcadoo.view.internal.components.FieldComponentPattern;
import com.qcadoo.view.internal.components.grid.GridComponentPattern;
import com.qcadoo.view.internal.components.window.WindowComponentPattern;
import com.qcadoo.view.internal.internal.ViewDefinitionImpl;
import com.qcadoo.view.internal.ribbon.model.InternalRibbon;
import com.qcadoo.view.internal.ribbon.model.InternalRibbonActionItem;
import com.qcadoo.view.internal.ribbon.model.InternalRibbonGroup;
import com.qcadoo.view.internal.ribbon.model.RibbonActionItemImpl;
import com.qcadoo.view.internal.ribbon.model.RibbonGroupImpl;
import com.qcadoo.view.internal.ribbon.model.RibbonImpl;
import com.qcadoo.view.internal.ribbon.model.SingleRibbonGroupPack;
import com.qcadoo.view.internal.xml.ViewDefinitionParser;
import com.qcadoo.view.internal.xml.ViewDefinitionParserNodeException;
public class LookupComponentPattern extends FieldComponentPattern {
private static final String L_LOOKUP_CODE = "lookupCode";
private static final String L_VALUE = "value";
private static final String L_TRUE = "true";
private static final String JSP_PATH = "elements/lookup.jsp";
private static final String JS_OBJECT = "QCD.components.elements.Lookup";
private boolean textRepresentationOnDisabled;
private boolean boldTextRepresentationOnDisabled;
private String expression;
private String fieldCode;
private boolean header = false;
private boolean prioritizable = true;
private boolean onlyActive = true;
private ModalDimensions modalDimensions;
private InternalViewDefinition lookupViewDefinition;
private RowStyleResolver rowStyleResolver;
private CriteriaModifier criteriaModifier;
public LookupComponentPattern(final ComponentDefinition componentDefinition) {
super(componentDefinition);
}
@Override
public ComponentState getComponentStateInstance() {
if (getScopeFieldDefinition() == null) {
return new LookupComponentState(null, fieldCode, expression, this);
}
String joinFieldName = null;
if (getScopeFieldDefinition().getType() instanceof JoinFieldHolder) {
joinFieldName = ((JoinFieldHolder) getScopeFieldDefinition().getType()).getJoinFieldName();
}
FieldDefinition fieldDefinition = getDataDefinition().getField(joinFieldName);
return new LookupComponentState(fieldDefinition, fieldCode, expression, this);
}
@Override
public String getJspFilePath() {
return JSP_PATH;
}
@Override
public String getJsFilePath() {
return JS_PATH;
}
@Override
public String getJsObjectName() {
return JS_OBJECT;
}
@Override
public void parse(final Node componentNode, final ViewDefinitionParser parser) throws ViewDefinitionParserNodeException {
super.parse(componentNode, parser);
final NodeList childNodes = componentNode.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node child = childNodes.item(i);
if (RowStyleResolver.NODE_NAME.equals(child.getNodeName())) {
rowStyleResolver = new RowStyleResolver(child, parser, getApplicationContext());
} else if (CriteriaModifier.NODE_NAME.equals(child.getNodeName())) {
criteriaModifier = new CriteriaModifier(child, parser, getApplicationContext());
}
}
}
@Override
protected void initializeComponent() throws JSONException {
super.initializeComponent();
for (ComponentOption option : getOptions()) {
if ("expression".equals(option.getType())) {
expression = option.getValue();
} else if ("fieldCode".equals(option.getType())) {
fieldCode = option.getValue();
} else if ("header".equals(option.getType())) {
header = Boolean.parseBoolean(option.getValue());
} else if ("prioritizable".equals(option.getType())) {
prioritizable = Boolean.parseBoolean(option.getValue());
} else if ("onlyActive".equals(option.getType())) {
onlyActive = Boolean.parseBoolean(option.getValue());
} else if ("textRepresentationOnDisabled".equals(option.getType())) {
textRepresentationOnDisabled = Boolean.parseBoolean(option.getValue());
} else if ("boldTextRepresentationOnDisabled".equals(option.getType())) {
Boolean optionValue = Boolean.parseBoolean(option.getValue());
textRepresentationOnDisabled = optionValue;
boldTextRepresentationOnDisabled = optionValue;
}
}
modalDimensions = ModalDimensions.parseFromOptions(getOptions());
checkState(hasText(fieldCode), "Missing fieldCode for lookup");
checkState(hasText(expression), "Missing expression for lookup");
String viewName = getViewName();
DataDefinition dataDefinition = getDataDefinition();
if (getScopeFieldDefinition() != null) {
dataDefinition = getScopeFieldDefinition().getDataDefinition();
}
lookupViewDefinition = new ViewDefinitionImpl(viewName, getViewDefinition().getPluginIdentifier(), dataDefinition, false,
getTranslationService());
WindowComponentPattern window = createWindowComponentPattern(lookupViewDefinition);
GridComponentPattern grid = createGridComponentPattern(lookupViewDefinition, window);
for (ComponentOption option : getOptions()) {
if ("expression".equals(option.getType())) {
continue;
} else if ("fieldCode".equals(option.getType())) {
continue;
} else if ("textRepresentationOnDisabled".equals(option.getType())) {
continue;
} else if ("labelWidth".equals(option.getType())) {
continue;
} else if ("orderable".equals(option.getType())) {
Map<String, String> newAttributes = new HashMap<String, String>();
newAttributes.put(L_VALUE, option.getValue() + ",lookupCode");
option = new ComponentOption("orderable", newAttributes);
grid.addOption(option);
} else if ("searchable".equals(option.getType())) {
Map<String, String> newAttributes = new HashMap<String, String>();
newAttributes.put(L_VALUE, option.getValue() + ",lookupCode");
option = new ComponentOption("searchable", newAttributes);
grid.addOption(option);
} else {
grid.addOption(option);
}
}
grid.addOption(new ComponentOption("lookup", Collections.singletonMap(L_VALUE, L_TRUE)));
window.addChild(grid);
lookupViewDefinition.addComponentPattern(window);
lookupViewDefinition.initialize();
}
@Override
protected JSONObject getJsOptions(final Locale locale) throws JSONException {
JSONObject json = new JSONObject();
json.put("viewName", getViewName());
json.put("modalDimensions", modalDimensions.toJson());
JSONObject translations = new JSONObject();
if (getFieldDefinition() == null) {
translations.put("labelOnFocus", getTranslationService().translate(getTranslationPath() + ".label.focus", locale));
} else {
String code = getFieldDefinition().getDataDefinition().getPluginIdentifier() + "."
+ getFieldDefinition().getDataDefinition().getName() + "." + getFieldDefinition().getName() + ".label.focus";
translations.put("labelOnFocus",
getTranslationService().translate(getTranslationPath() + ".label.focus", code, locale));
}
translations.put(
"noMatchError",
getTranslationService().translate(getTranslationPath() + ".noMatchError", "qcadooView.lookup.noMatchError",
locale));
translations.put(
"moreTahnOneMatchError",
getTranslationService().translate(getTranslationPath() + ".moreTahnOneMatchError",
"qcadooView.lookup.moreTahnOneMatchError", locale));
translations.put(
"noResultsInfo",
getTranslationService().translate(getTranslationPath() + ".noResultsInfo", "qcadooView.lookup.noResultsInfo",
locale));
translations.put(
"tooManyResultsInfo",
getTranslationService().translate(getTranslationPath() + ".tooManyResultsInfo",
"qcadooView.lookup.tooManyResultsInfo", locale));
json.put("translations", translations);
return json;
}
@Override
protected Map<String, Object> getJspOptions(final Locale locale) {
Map<String, Object> options = super.getJspOptions(locale);
options.put("textRepresentationOnDisabled", textRepresentationOnDisabled);
options.put("boldTextRepresentationOnDisabled", boldTextRepresentationOnDisabled);
return options;
}
@Override
protected void registerComponentViews(final InternalViewDefinitionService viewDefinitionService) {
viewDefinitionService.save(lookupViewDefinition);
}
@Override
protected void unregisterComponentViews(final InternalViewDefinitionService viewDefinitionService) {
viewDefinitionService.delete(lookupViewDefinition);
}
public CriteriaModifier getCriteriaModifier() {
return criteriaModifier;
}
private GridComponentPattern createGridComponentPattern(final ViewDefinition lookupViewDefinition,
final WindowComponentPattern window) {
final ComponentDefinition gridComponentDefinition = new ComponentDefinition();
gridComponentDefinition.setName("grid");
gridComponentDefinition.setTranslationService(getTranslationService());
gridComponentDefinition.setApplicationContext(getApplicationContext());
gridComponentDefinition.setViewDefinition(lookupViewDefinition);
gridComponentDefinition.setParent(window);
gridComponentDefinition.setContextualHelpService(getContextualHelpService());
gridComponentDefinition.setReference("grid");
if (getScopeFieldDefinition() != null) {
gridComponentDefinition.setSourceFieldPath(getScopeFieldDefinition().getName());
}
final GridComponentPattern grid = new GridComponentPattern(gridComponentDefinition);
grid.setRowStyleResolver(rowStyleResolver);
grid.setCriteriaModifier(criteriaModifier);
grid.addOption(new ComponentOption("lookup", ImmutableMap.of(L_VALUE, L_TRUE)));
grid.addOption(new ComponentOption("fullscreen", ImmutableMap.of(L_VALUE, L_TRUE)));
grid.addOption(new ComponentOption("orderable", ImmutableMap.of(L_VALUE, L_LOOKUP_CODE)));
grid.addOption(new ComponentOption("order", ImmutableMap.of("column", L_LOOKUP_CODE, "direction", "asc")));
grid.addOption(new ComponentOption("searchable", ImmutableMap.of(L_VALUE, L_LOOKUP_CODE)));
grid.addOption(new ComponentOption("prioritizable", ImmutableMap.of(L_VALUE, Boolean.toString(prioritizable))));
grid.addOption(new ComponentOption("onlyActive", ImmutableMap.of(L_VALUE, Boolean.toString(onlyActive))));
grid.addOption(createLookupCodeColumn());
grid.addOption(createLookupValueColumn());
return grid;
}
private ComponentOption createLookupValueColumn() {
Map<String, String> valueColumnOptions = new HashMap<String, String>();
valueColumnOptions.put("name", "lookupValue");
valueColumnOptions.put("expression", expression);
valueColumnOptions.put("hidden", L_TRUE);
return new ComponentOption("column", valueColumnOptions);
}
private ComponentOption createLookupCodeColumn() {
Map<String, String> codeVisibleColumnOptions = new HashMap<String, String>();
codeVisibleColumnOptions.put("name", L_LOOKUP_CODE);
codeVisibleColumnOptions.put("fields", fieldCode);
codeVisibleColumnOptions.put("hidden", "false");
codeVisibleColumnOptions.put("link", L_TRUE);
return new ComponentOption("column", codeVisibleColumnOptions);
}
private WindowComponentPattern createWindowComponentPattern(final ViewDefinition lookupViewDefinition) {
ComponentDefinition windowComponentDefinition = new ComponentDefinition();
windowComponentDefinition.setName("window");
windowComponentDefinition.setTranslationService(getTranslationService());
windowComponentDefinition.setApplicationContext(getApplicationContext());
windowComponentDefinition.setViewDefinition(lookupViewDefinition);
windowComponentDefinition.setContextualHelpService(getContextualHelpService());
WindowComponentPattern window = new WindowComponentPattern(windowComponentDefinition);
window.setFixedHeight(true);
window.setHeader(header);
window.setRibbon(createRibbon());
return window;
}
private InternalRibbon createRibbon() {
InternalRibbonActionItem ribbonSelectActionItem = new RibbonActionItemImpl();
ribbonSelectActionItem.setName("select");
ribbonSelectActionItem.setIcon("acceptIcon24.png");
ribbonSelectActionItem.setAction("#{window.grid}.performLinkClicked();");
ribbonSelectActionItem.setType(Type.BIG_BUTTON);
ribbonSelectActionItem.setEnabled(false);
ribbonSelectActionItem.setDefaultEnabled(false);
ribbonSelectActionItem.setMessage("#{translate(noRecordSelected)}");
ribbonSelectActionItem
.setScript("#{grid}.addOnChangeListener({onChange: function(selectedArray) {if (!selectedArray || selectedArray.length == 0) {"
+ "this.disable('#{translate(noRecordSelected)}');} else {this.enable();}}});");
InternalRibbonActionItem ribbonCancelActionItem = new RibbonActionItemImpl();
ribbonCancelActionItem.setName("cancel");
ribbonCancelActionItem.setIcon("cancelIcon24.png");
ribbonCancelActionItem.setAction("#{window}.closeThisModalWindow(false)");
ribbonCancelActionItem.setType(Type.BIG_BUTTON);
ribbonCancelActionItem.setEnabled(true);
InternalRibbonGroup ribbonGroup = new RibbonGroupImpl("navigation");
ribbonGroup.addItem(ribbonSelectActionItem);
ribbonGroup.addItem(ribbonCancelActionItem);
InternalRibbon ribbon = new RibbonImpl();
ribbon.addGroupsPack(new SingleRibbonGroupPack(ribbonGroup));
return ribbon;
}
private String getViewName() {
return getViewDefinition().getName() + "." + getFunctionalPath() + ".lookup";
}
public boolean isOnlyActive() {
return onlyActive;
}
}