/* * Catroid: An on-device visual programming system for Android devices * Copyright (C) 2010-2016 The Catrobat Team * (<http://developer.catrobat.org/credits>) * * 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. * * An additional term exception under section 7 of the GNU Affero * General Public License, version 3, is available at * http://developer.catrobat.org/license_additional_term * * 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/>. */ package org.catrobat.catroid.content.bricks; import android.content.Context; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.BaseAdapter; import android.widget.EditText; import android.widget.TextView; import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction; import com.thoughtworks.xstream.annotations.XStreamAlias; import org.catrobat.catroid.ProjectManager; import org.catrobat.catroid.R; import org.catrobat.catroid.content.ActionFactory; import org.catrobat.catroid.content.Sprite; import org.catrobat.catroid.formulaeditor.DataContainer; import org.catrobat.catroid.formulaeditor.Formula; import org.catrobat.catroid.formulaeditor.InterpretationException; import org.catrobat.catroid.formulaeditor.UserVariable; import org.catrobat.catroid.ui.BrickLayout; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class UserBrick extends BrickBaseType implements OnClickListener { private static final long serialVersionUID = 1L; private static final String TAG = UserBrick.class.getSimpleName(); @XStreamAlias("definitionBrick") private UserScriptDefinitionBrick definitionBrick; private transient View prototypeView; @XStreamAlias("userBrickParameters") private List<UserBrickParameter> userBrickParameters = new ArrayList<>(); public UserBrick() { this.definitionBrick = new UserScriptDefinitionBrick(); } public UserBrick(UserScriptDefinitionBrick definitionBrick) { this.definitionBrick = definitionBrick; } @Override public int getRequiredResources() { return definitionBrick.getRequiredResources(); } @Override public UserBrick copyBrickForSprite(Sprite sprite) { UserBrick clonedBrick = (UserBrick) clone(); clonedBrick.definitionBrick = (UserScriptDefinitionBrick) definitionBrick.copyBrickForSprite(sprite); return clonedBrick; } @Override public Brick clone() { animationState = false; UserBrick clonedUserBrick = new UserBrick(definitionBrick); clonedUserBrick.userBrickParameters = new ArrayList<>(); if (userBrickParameters != null) { for (int position = 0; position < userBrickParameters.size(); position++) { UserBrickParameter userBrickParameter = userBrickParameters.get(position); clonedUserBrick.userBrickParameters.add(userBrickParameter.clone()); } } return clonedUserBrick; } public List<UserBrickParameter> getUserBrickParameters() { return userBrickParameters; } private UserBrickParameter getUserBrickParameterByUserBrickElement(UserScriptDefinitionBrickElement element) { if (userBrickParameters == null) { return null; } for (UserBrickParameter parameter : userBrickParameters) { if (parameter.getElement().equals(element)) { return parameter; } } return null; } public void updateUserBrickParametersAndVariables() { updateUserBrickParameters(); updateUserVariableValues(); } public void updateUserBrickParameters() { List<UserBrickParameter> newParameters = new ArrayList<>(); List<UserScriptDefinitionBrickElement> elements = getUserScriptDefinitionBrickElements(); for (UserScriptDefinitionBrickElement element : elements) { if (!element.isVariable()) { continue; } UserBrickParameter parameter = getUserBrickParameterByUserBrickElement(element); if (parameter == null) { parameter = new UserBrickParameter(this, element); parameter.setFormulaWithBrickField(BrickField.USER_BRICK, new Formula(0)); } newParameters.add(parameter); } if (userBrickParameters != null) { copyFormulasMatchingNames(userBrickParameters, newParameters); } userBrickParameters = newParameters; } public void copyFormulasMatchingNames(List<UserBrickParameter> originalParameters, List<UserBrickParameter> copiedParameters) { for (UserBrickParameter originalParameter : originalParameters) { UserScriptDefinitionBrickElement originalElement = originalParameter.getElement(); if (!originalElement.isVariable()) { return; } for (UserBrickParameter copiedParameter : copiedParameters) { UserScriptDefinitionBrickElement copiedElement = copiedParameter.getElement(); if (originalElement.equals(copiedElement)) { Formula formula = originalParameter.getFormulaWithBrickField(BrickField.USER_BRICK); copiedParameter.setFormulaWithBrickField(BrickField.USER_BRICK, formula.clone()); } } } } private void updateUserVariableValues() { DataContainer dataContainer = ProjectManager.getInstance().getCurrentScene().getDataContainer(); List<UserVariable> variables = new ArrayList<>(); for (UserBrickParameter userBrickParameter : userBrickParameters) { UserScriptDefinitionBrickElement element = userBrickParameter.getElement(); if (element != null) { List<Formula> formulas = userBrickParameter.getFormulas(); Sprite sprite = ProjectManager.getInstance().getCurrentSprite(); try { for (Formula formula : formulas) { variables.add(new UserVariable(element.getText(), formula.interpretDouble(sprite))); } } catch (InterpretationException e) { Log.e(TAG, e.getMessage()); } } } if (variables.isEmpty()) { return; } dataContainer.setUserBrickVariables(this, variables); Sprite currentSprite = ProjectManager.getInstance().getCurrentSprite(); if (currentSprite != null) { currentSprite.updateUserVariableReferencesInUserVariableBricks(variables); } } public List<Formula> getFormulas() { List<Formula> formulaList = new LinkedList<>(); for (UserBrickParameter parameter : userBrickParameters) { UserScriptDefinitionBrickElement element = parameter.getElement(); Formula formula = parameter.getFormulaWithBrickField(BrickField.USER_BRICK); if (formula != null && element != null && element.isVariable()) { formulaList.add(formula); } } return formulaList; } public void appendBrickToScript(Brick brick) { definitionBrick.appendBrickToScript(brick); } @Override public View getView(Context context, int brickId, BaseAdapter baseAdapter) { if (animationState) { return view; } setUserBrickParametersParent(); view = View.inflate(context, R.layout.brick_user, null); view = BrickViewProvider.setAlphaOnView(view, alphaValue); setCheckboxView(R.id.brick_user_checkbox); onLayoutChanged(view); return view; } private void setUserBrickParametersParent() { if (userBrickParameters != null) { for (UserBrickParameter parameter : userBrickParameters) { parameter.setParent(this); } } } @Override public View getPrototypeView(Context context) { prototypeView = View.inflate(context, R.layout.brick_user, null); onLayoutChanged(prototypeView); return prototypeView; } public void onLayoutChanged(View currentView) { boolean prototype = (currentView == prototypeView); Context context = currentView.getContext(); BrickLayout layout = (BrickLayout) currentView.findViewById(R.id.brick_user_flow_layout); if (layout.getChildCount() > 0) { layout.removeAllViews(); } int id = 0; for (UserScriptDefinitionBrickElement element : getUserScriptDefinitionBrickElements()) { TextView currentEditText; if (element.isLineBreak()) { continue; } else if (element.isVariable()) { UserBrickParameter parameter = getUserBrickParameterByUserBrickElement(element); currentEditText = new EditText(context); currentEditText.setId(id); currentEditText.setTextAppearance(context, R.style.BrickEditText); if (parameter != null) { parameter.getFormulaWithBrickField(BrickField.USER_BRICK).setTextFieldId(currentEditText.getId()); String formulaString = parameter.getFormulaWithBrickField(BrickField.USER_BRICK).getDisplayString(currentEditText.getContext()); parameter.getFormulaWithBrickField(BrickField.USER_BRICK).refreshTextField(currentEditText, formulaString); } // This stuff isn't being included by the style when I use setTextAppearance. currentEditText.setFocusable(false); currentEditText.setFocusableInTouchMode(false); currentEditText.setOnClickListener(this); currentEditText.setVisibility(View.VISIBLE); if (parameter != null) { if (prototype) { parameter.setPrototypeView(currentEditText); } else { parameter.setTextView(currentEditText); } } } else { currentEditText = new TextView(context); currentEditText.setTextAppearance(context, R.style.BrickText_Multiple); currentEditText.setText(element.getText()); } // This stuff isn't being included by the style when I use setTextAppearance. if (prototype) { currentEditText.setFocusable(false); currentEditText.setFocusableInTouchMode(false); currentEditText.setClickable(false); } layout.addView(currentEditText); if (element.isNewLineHint()) { BrickLayout.LayoutParams params = (BrickLayout.LayoutParams) currentEditText.getLayoutParams(); params.setNewLine(true); currentEditText.setLayoutParams(params); } id++; } } @Override public void onClick(View eventOrigin) { if (checkbox.getVisibility() == View.VISIBLE) { return; } for (UserBrickParameter userBrickParameter : userBrickParameters) { int currentUserBrickParameterIndex = userBrickParameter.getTextView().getId(); int clickedUserBrickParameterIndex = eventOrigin.getId(); if (currentUserBrickParameterIndex == clickedUserBrickParameterIndex) { userBrickParameter.showFormulaEditorToEditFormula(view); } } } @Override public List<SequenceAction> addActionToSequence(Sprite sprite, SequenceAction sequence) { updateUserVariableValues(); List<SequenceAction> returnActionList = new ArrayList<>(); ActionFactory actionFactory = sprite.getActionFactory(); SequenceAction userSequence = (SequenceAction) actionFactory.createSequence(); definitionBrick.getScriptSafe().run(sprite, userSequence); returnActionList.add(userSequence); sequence.addAction(actionFactory.createUserBrickAction(userSequence, this)); ProjectManager.getInstance().setCurrentUserBrick(this); if (sprite.isClone) { sprite.addUserBrick(this); } return returnActionList; } public UserScriptDefinitionBrick getDefinitionBrick() { return definitionBrick; } public void setDefinitionBrick(UserScriptDefinitionBrick definitionBrick) { this.definitionBrick = definitionBrick; } public List<UserScriptDefinitionBrickElement> getUserScriptDefinitionBrickElements() { return definitionBrick.getUserScriptDefinitionBrickElements(); } @Override public void storeDataForBackPack(Sprite sprite) { definitionBrick = (UserScriptDefinitionBrick) definitionBrick.copyBrickForSprite(sprite); for (Brick brick : definitionBrick.getUserScript().getBrickList()) { brick.storeDataForBackPack(sprite); } } }