/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2014 Servoy BV This program 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, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.mozilla.javascript.NativeArray; import org.mozilla.javascript.Scriptable; import com.servoy.j2db.dataprocessing.EditRecordList; import com.servoy.j2db.dataprocessing.ISaveConstants; import com.servoy.j2db.persistence.Form; import com.servoy.j2db.scripting.FormScope; import com.servoy.j2db.scripting.GlobalScope; import com.servoy.j2db.scripting.ScopesScope; import com.servoy.j2db.scripting.SolutionScope; /** * @author jcompagner * */ public abstract class BasicFormManager implements IBasicFormManager { protected final ConcurrentMap<String, Form> possibleForms; // formName -> Form protected final IApplication application; public BasicFormManager(IApplication application) { this.application = application; possibleForms = new ConcurrentHashMap<String, Form>(); } public void addForm(Form form, boolean selected) { Form f = possibleForms.put(form.getName(), form); if (f != null && form != f) { // replace all occurrences to the previous form to this new form (newFormInstances) Iterator<Entry<String, Form>> iterator = possibleForms.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, Form> next = iterator.next(); if (next.getValue() == f) { next.setValue(form); } } } } public boolean removeForm(Form form) { boolean removed = destroyFormInstance(form.getName()); if (removed) { possibleForms.remove(form.getName()); } return removed; } public Iterator<String> getPossibleFormNames() { return possibleForms.keySet().iterator(); } public Form getPossibleForm(String name) { return possibleForms.get(name); } public boolean isPossibleForm(String formName) { return possibleForms.containsKey(formName); } public boolean createNewFormInstance(String designFormName, String newInstanceScriptName) { Form f = possibleForms.get(designFormName); Form test = possibleForms.get(newInstanceScriptName); if (f != null && test == null) { possibleForms.put(newInstanceScriptName, f); return true; } return false; } public boolean destroyFormInstance(String formName) { Form test = possibleForms.get(formName); if (test != null) { // If form found, test if there is a formcontroller alive. IFormController fc = getCachedFormController(formName); if (fc != null) { // if that one can be deleted destroy it. if (!canBeDeleted(fc)) { return false; } fc.destroy(); } // if the formname is an alias then remove the alias. if (!test.getName().equals(formName)) { possibleForms.remove(formName); } setFormReadOnly(formName, false); return true; } return false; } protected boolean canBeDeleted(IFormController fp) { if (fp.isFormVisible()) { return false; } // cannot be deleted if a global var has a ref ScopesScope scopesScope = application.getScriptEngine().getScopesScope(); if (hasReferenceInScriptable(scopesScope, fp, new HashSet<Scriptable>())) { return false; } if (fp.isFormExecutingFunction()) { return false; } // if this controller uses a separate foundset if (fp.getForm().getUseSeparateFoundSet()) { // test if that foundset has edited records that can't be saved EditRecordList editRecordList = application.getFoundSetManager().getEditRecordList(); if (editRecordList.stopIfEditing(fp.getFoundSet()) != ISaveConstants.STOPPED) { return false; } } // the cached currentcontroller may not be destroyed SolutionScope ss = application.getScriptEngine().getSolutionScope(); return ss == null || fp.initForJSUsage() != ss.get("currentcontroller", ss); //$NON-NLS-1$ } private boolean hasReferenceInScriptable(Scriptable scriptVar, IFormController fc, Set<Scriptable> seen) { if (!seen.add(scriptVar)) { // endless recursion return false; } if (scriptVar instanceof FormScope) { return ((FormScope)scriptVar).getFormController().equals(fc); } if (scriptVar instanceof GlobalScope || scriptVar instanceof ScopesScope || scriptVar instanceof NativeArray) // if(o instanceof Scriptable) for all scriptable ? { Object[] propertyIDs = scriptVar.getIds(); if (propertyIDs != null) { Object propertyValue; for (Object element : propertyIDs) { if (element != null) { if (element instanceof Integer) { propertyValue = scriptVar.get(((Integer)element).intValue(), scriptVar); } else { propertyValue = scriptVar.get(element.toString(), scriptVar); } if (propertyValue != null && propertyValue.equals(fc)) { return true; } if (propertyValue instanceof Scriptable && hasReferenceInScriptable((Scriptable)propertyValue, fc, seen)) { return true; } } } } } return false; } public boolean isFormReadOnly(String formName) { return readOnlyCheck.contains(formName); } protected List<String> readOnlyCheck = new ArrayList<String>(); public void setFormReadOnly(String formName, boolean readOnly) { if (readOnly && readOnlyCheck.contains(formName)) return; if (readOnly) { readOnlyCheck.add(formName); } else { readOnlyCheck.remove(formName); } } public boolean isFormEnabled(String formName) { return !enabledCheck.contains(formName); } protected List<String> enabledCheck = new ArrayList<String>(); public void setFormEnabled(String formName, boolean enabled) { if (!enabled && enabledCheck.contains(formName)) return; if (!enabled) { enabledCheck.add(formName); } else { enabledCheck.remove(formName); } } /** * @param formName * @return */ public abstract IFormController getCachedFormController(String formName); }