/* * 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.ui.fragment; import android.app.ActionBar; import android.app.Activity; import android.app.AlertDialog; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.provider.Settings; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnKeyListener; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TableLayout; import android.widget.TableRow; import org.catrobat.catroid.ProjectManager; import org.catrobat.catroid.R; import org.catrobat.catroid.content.bricks.Brick; import org.catrobat.catroid.content.bricks.FormulaBrick; import org.catrobat.catroid.content.bricks.UserBrick; import org.catrobat.catroid.content.bricks.UserBrickParameter; import org.catrobat.catroid.content.commands.OnFormulaChangedListener; import org.catrobat.catroid.formulaeditor.Formula; import org.catrobat.catroid.formulaeditor.FormulaEditorEditText; import org.catrobat.catroid.formulaeditor.FormulaElement; import org.catrobat.catroid.formulaeditor.InternFormulaKeyboardAdapter; import org.catrobat.catroid.formulaeditor.InternFormulaParser; import org.catrobat.catroid.formulaeditor.SensorHandler; import org.catrobat.catroid.ui.BottomBar; import org.catrobat.catroid.ui.ScriptActivity; import org.catrobat.catroid.ui.dialogs.CustomAlertDialogBuilder; import org.catrobat.catroid.ui.dialogs.FormulaEditorComputeDialog; import org.catrobat.catroid.ui.dialogs.NewStringDialog; import org.catrobat.catroid.utils.ToastUtil; public class FormulaEditorFragment extends Fragment implements OnKeyListener, ViewTreeObserver.OnGlobalLayoutListener { private static final String TAG = FormulaEditorFragment.class.getSimpleName(); private static final int PARSER_OK = -1; private static final int PARSER_STACK_OVERFLOW = -2; private static final int PARSER_INPUT_SYNTAX_ERROR = -3; private static final int SET_FORMULA_ON_CREATE_VIEW = 0; private static final int SET_FORMULA_ON_SWITCH_EDIT_TEXT = 1; private static final int TIME_WINDOW = 2000; public static final int REQUEST_GPS = 1; public static final String FORMULA_EDITOR_FRAGMENT_TAG = FormulaEditorFragment.class.getSimpleName(); public static final String FORMULA_BRICK_BUNDLE_ARGUMENT = "formula_brick"; public static final String BRICKFIELD_BUNDLE_ARGUMENT = "brick_field"; private Context context; private static FormulaEditorEditText formulaEditorEditText; private TableLayout formulaEditorKeyboard; private static LinearLayout formulaEditorBrick; private static View brickView; private View fragmentView; private static FormulaBrick formulaBrick; private FormulaBrick clonedFormulaBrick; private static Brick.BrickField currentBrickField; private static Formula currentFormula; private Menu currentMenu; private FormulaElement formulaElementForComputeDialog; private long[] confirmSwitchEditTextTimeStamp = { 0, 0 }; private int confirmSwitchEditTextCounter = 0; private CharSequence previousActionBarTitle; private VariableOrUserListDeletedReceiver variableOrUserListDeletedReceiver; private static OnFormulaChangedListener onFormulaChangedListener; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(!ViewConfiguration.get(getActivity()).hasPermanentMenuKey()); setUpActionBar(); onFormulaChangedListener = (OnFormulaChangedListener) ((ScriptActivity) getActivity()) .getFragment(ScriptActivity.FRAGMENT_SCRIPTS); formulaBrick = (FormulaBrick) getArguments().getSerializable(FORMULA_BRICK_BUNDLE_ARGUMENT); currentBrickField = Brick.BrickField.valueOf(getArguments().getString(BRICKFIELD_BUNDLE_ARGUMENT)); cloneFormulaBrick(formulaBrick); currentFormula = clonedFormulaBrick.getFormulaWithBrickField(currentBrickField); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); } private void setUpActionBar() { ActionBar actionBar = getActivity().getActionBar(); previousActionBarTitle = ProjectManager.getInstance().getCurrentSprite().getName(); actionBar.setDisplayShowTitleEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setTitle(R.string.formula_editor_title); } private void resetActionBar() { ActionBar actionBar = getActivity().getActionBar(); actionBar.setTitle(previousActionBarTitle); } private void cloneFormulaBrick(FormulaBrick formulaBrick) { try { clonedFormulaBrick = (FormulaBrick) formulaBrick.clone(); clonedFormulaBrick.setCommentedOut(formulaBrick.isCommentedOut()); } catch (CloneNotSupportedException exception) { Log.e(TAG, "Clone not supported", exception); onUserDismiss(); } } private static void showFragment(View view, FormulaBrick formulaBrick, Brick.BrickField brickField, boolean showCustomView) { Activity activity = (Activity) view.getContext(); FormulaEditorFragment formulaEditorFragment = (FormulaEditorFragment) activity.getFragmentManager() .findFragmentByTag(FORMULA_EDITOR_FRAGMENT_TAG); FragmentManager fragmentManager = activity.getFragmentManager(); FragmentTransaction fragTransaction = fragmentManager.beginTransaction(); if (formulaEditorFragment == null) { formulaEditorFragment = new FormulaEditorFragment(); formulaEditorFragment.showCustomView = showCustomView; Bundle bundle = new Bundle(); bundle.putSerializable(FORMULA_BRICK_BUNDLE_ARGUMENT, formulaBrick); bundle.putString(BRICKFIELD_BUNDLE_ARGUMENT, brickField.name()); formulaEditorFragment.setArguments(bundle); fragTransaction.add(R.id.fragment_container, formulaEditorFragment, FORMULA_EDITOR_FRAGMENT_TAG); fragTransaction.hide(fragmentManager.findFragmentByTag(ScriptFragment.TAG)); fragTransaction.show(formulaEditorFragment); BottomBar.hideBottomBar(activity); } else if (formulaEditorFragment.isHidden()) { formulaEditorFragment.showCustomView = showCustomView; formulaEditorFragment.updateBrickViewAndFormula(formulaBrick, brickField); fragTransaction.hide(fragmentManager.findFragmentByTag(ScriptFragment.TAG)); fragTransaction.show(formulaEditorFragment); BottomBar.hideBottomBar(activity); } else { refreshUserBrickParameterValuesIfNecessary(formulaBrick, brickField, formulaEditorFragment); formulaEditorFragment.showCustomView = false; formulaEditorFragment.updateBrickView(); formulaEditorFragment.setInputFormula(brickField, SET_FORMULA_ON_SWITCH_EDIT_TEXT); } fragTransaction.commit(); } public static boolean saveFormulaForUserBrickParameterChange() { InternFormulaParser formulaToParse = formulaEditorEditText.getFormulaParser(); FormulaElement formulaParseTree = formulaToParse.parseFormula(); switch (formulaToParse.getErrorTokenIndex()) { case PARSER_OK: currentFormula.setRoot(formulaParseTree); if (onFormulaChangedListener != null) { onFormulaChangedListener.onFormulaChanged(formulaBrick, currentBrickField, currentFormula); } if (formulaEditorBrick != null) { currentFormula.refreshTextField(brickView); } formulaEditorEditText.formulaSaved(); return true; } return false; } private static void refreshUserBrickParameterValuesIfNecessary(FormulaBrick formulaBrick, Brick.BrickField brickField, FormulaEditorFragment formulaEditorFragment) { if (formulaBrick instanceof UserBrickParameter) { saveFormulaForUserBrickParameterChange(); updateUserBricksIfNecessary(); formulaEditorFragment.updateBrickViewAndFormula(formulaBrick, brickField); updateUserBricksIfNecessary(); } } private boolean showCustomView = false; public static void showFragment(View view, FormulaBrick formulaBrick, Brick.BrickField brickField) { showFragment(view, formulaBrick, brickField, false); } public static void showCustomFragment(View view, FormulaBrick formulaBrick, Brick.BrickField brickField) { showFragment(view, formulaBrick, brickField, true); } public static void overwriteFormula(View view, Formula newFormula) { Activity activity = (Activity) view.getContext(); FormulaEditorFragment formulaEditorFragment = (FormulaEditorFragment) activity.getFragmentManager() .findFragmentByTag(FORMULA_EDITOR_FRAGMENT_TAG); if (formulaEditorFragment == null) { return; } formulaEditorFragment.formulaEditorEditText.overwriteCurrentFormula(newFormula.getInternFormulaState()); } public static void changeInputField(View view, Brick.BrickField brickField) { Activity activity = (Activity) view.getContext(); FormulaEditorFragment formulaEditorFragment = (FormulaEditorFragment) activity.getFragmentManager() .findFragmentByTag(FORMULA_EDITOR_FRAGMENT_TAG); if (formulaEditorFragment == null) { return; } formulaEditorFragment.setInputFormula(brickField, SET_FORMULA_ON_SWITCH_EDIT_TEXT); } public void updateBrickView() { View newBrickView = getBrickOrCustomView(); setBrickViewSafe(newBrickView, true); fragmentView.getViewTreeObserver().addOnGlobalLayoutListener(this); handleCustomView(); } private void setBrickViewSafe(View newBrickView, boolean removeAllViews) { if (newBrickView != null) { if (newBrickView.getParent() != null) { ((LinearLayout) newBrickView.getParent()).removeView(newBrickView); } if (removeAllViews && formulaEditorBrick.getChildCount() > 0) { formulaEditorBrick.removeAllViews(); } formulaEditorBrick.addView(newBrickView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)); brickView = newBrickView; } } private void updateBrickViewAndFormula(FormulaBrick newBrick, Brick.BrickField brickField) { formulaBrick = newBrick; cloneFormulaBrick(newBrick); updateBrickView(); currentBrickField = brickField; currentFormula = clonedFormulaBrick.getFormulaWithBrickField(brickField); setInputFormula(currentBrickField, SET_FORMULA_ON_CREATE_VIEW); fragmentView.getViewTreeObserver().addOnGlobalLayoutListener(this); updateButtonsOnKeyboardAndInvalidateOptionsMenu(); } private void onUserDismiss() { refreshFormulaPreviewString(currentFormula.getTrimmedFormulaString(getActivity())); formulaEditorEditText.endEdit(); currentFormula.prepareToRemove(); Activity activity = getActivity(); FragmentManager fragmentManager = activity.getFragmentManager(); FragmentTransaction fragTransaction = fragmentManager.beginTransaction(); fragTransaction.hide(this); fragTransaction.show(fragmentManager.findFragmentByTag(ScriptFragment.TAG)); fragTransaction.commit(); resetActionBar(); BottomBar.showBottomBar(activity); BottomBar.showPlayButton(activity); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { fragmentView = inflater.inflate(R.layout.fragment_formula_editor, container, false); fragmentView.setFocusableInTouchMode(true); fragmentView.requestFocus(); context = getActivity(); brickView = getBrickOrCustomView(); formulaEditorBrick = (LinearLayout) fragmentView.findViewById(R.id.formula_editor_brick_space); setBrickViewSafe(brickView, false); formulaEditorEditText = (FormulaEditorEditText) fragmentView.findViewById(R.id.formula_editor_edit_field); formulaEditorKeyboard = (TableLayout) fragmentView.findViewById(R.id.formula_editor_keyboardview); formulaEditorEditText.init(this); fragmentView.getViewTreeObserver().addOnGlobalLayoutListener(this); setInputFormula(currentBrickField, SET_FORMULA_ON_CREATE_VIEW); setHasOptionsMenu(true); setUpActionBar(); handleCustomView(); return fragmentView; } private void handleCustomView() { if (showCustomView) { formulaEditorEditText.setVisibility(View.GONE); formulaEditorKeyboard.setVisibility(View.GONE); } else { formulaEditorEditText.setVisibility(View.VISIBLE); formulaEditorKeyboard.setVisibility(View.VISIBLE); } } private View getBrickOrCustomView() { if (showCustomView) { return clonedFormulaBrick.getCustomView(context, 0, null); } else { return clonedFormulaBrick.getView(context, 0, null); } } @Override public void onStart() { formulaEditorKeyboard.setClickable(true); getView().requestFocus(); View.OnTouchListener touchListener = new View.OnTouchListener() { private Handler handler; private Runnable deleteAction; private boolean handleLongClick(final View view, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { if (handler == null) { return true; } handler.removeCallbacks(deleteAction); handler = null; } if (event.getAction() == MotionEvent.ACTION_DOWN) { deleteAction = new Runnable() { @Override public void run() { handler.postDelayed(this, 100); if (formulaEditorEditText.isThereSomethingToDelete()) { formulaEditorEditText.handleKeyEvent(view.getId(), ""); } } }; if (handler != null) { return true; } handler = new Handler(); handler.postDelayed(deleteAction, 400); } return true; } @Override public boolean onTouch(View view, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { updateButtonsOnKeyboardAndInvalidateOptionsMenu(); view.setPressed(false); handleLongClick(view, event); return true; } if (event.getAction() == MotionEvent.ACTION_DOWN) { view.setPressed(true); switch (view.getId()) { case R.id.formula_editor_keyboard_compute: InternFormulaParser internFormulaParser = formulaEditorEditText.getFormulaParser(); FormulaElement formulaElement = internFormulaParser.parseFormula(); if (formulaElement == null) { if (internFormulaParser.getErrorTokenIndex() >= 0) { formulaEditorEditText.setParseErrorCursorAndSelection(); } return false; } if ((formulaElement.getRequiredResources() & Brick.SENSOR_GPS) > 0 && !SensorHandler .gpsAvailable()) { formulaElementForComputeDialog = formulaElement; Intent checkIntent = new Intent(); checkIntent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivityForResult(checkIntent, REQUEST_GPS); } else { showComputeDialog(formulaElement); } return true; case R.id.formula_editor_keyboard_function: showFormularEditorCategorylistFragment(FormulaEditorCategoryListFragment.FUNCTION_TAG, R.string.formula_editor_functions); return true; case R.id.formula_editor_keyboard_logic: showFormularEditorCategorylistFragment(FormulaEditorCategoryListFragment.LOGIC_TAG, R.string.formula_editor_logic); return true; case R.id.formula_editor_keyboard_object: showFormularEditorCategorylistFragment(FormulaEditorCategoryListFragment.OBJECT_TAG, R.string.formula_editor_choose_object_variable); return true; case R.id.formula_editor_keyboard_sensors: showFormularEditorCategorylistFragment(FormulaEditorCategoryListFragment.SENSOR_TAG, R.string.formula_editor_device); return true; case R.id.formula_editor_keyboard_data: showFormulaEditorDataFragment(FormulaEditorDataFragment.USER_DATA_TAG, R.string.formula_editor_data); return true; case R.id.formula_editor_keyboard_ok: endFormulaEditor(); return true; case R.id.formula_editor_keyboard_string: FragmentManager fragmentManager = ((Activity) context) .getFragmentManager(); Fragment dialogFragment = fragmentManager .findFragmentByTag(NewStringDialog.DIALOG_FRAGMENT_TAG); if (dialogFragment == null) { dialogFragment = NewStringDialog.newInstance(); } ((NewStringDialog) dialogFragment).show(fragmentManager, NewStringDialog.DIALOG_FRAGMENT_TAG); return true; case R.id.formula_editor_keyboard_delete: formulaEditorEditText.handleKeyEvent(view.getId(), ""); return handleLongClick(view, event); default: formulaEditorEditText.handleKeyEvent(view.getId(), ""); return true; } } return false; } }; for (int index = 0; index < formulaEditorKeyboard.getChildCount(); index++) { View tableRow = formulaEditorKeyboard.getChildAt(index); if (tableRow instanceof TableRow) { TableRow row = (TableRow) tableRow; for (int indexRow = 0; indexRow < row.getChildCount(); indexRow++) { row.getChildAt(indexRow).setOnTouchListener(touchListener); } } } updateButtonsOnKeyboardAndInvalidateOptionsMenu(); super.onStart(); } private void showComputeDialog(FormulaElement formulaElement) { if (formulaElement == null) { return; } Formula formulaToCompute = new Formula(formulaElement); FormulaEditorComputeDialog computeDialog = new FormulaEditorComputeDialog(context); computeDialog.setFormula(formulaToCompute); computeDialog.show(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_GPS && resultCode == Activity.RESULT_CANCELED && SensorHandler.gpsAvailable()) { showComputeDialog(formulaElementForComputeDialog); } else { showToast(R.string.error_gps_not_available, true); } } @Override public void onPrepareOptionsMenu(Menu menu) { currentMenu = menu; for (int index = 0; index < menu.size(); index++) { menu.getItem(index).setVisible(false); } MenuItem undo = menu.findItem(R.id.menu_undo); if (formulaEditorEditText == null || !formulaEditorEditText.getHistory().undoIsPossible()) { undo.setIcon(R.drawable.icon_undo_disabled); undo.setEnabled(false); } else { undo.setIcon(R.drawable.icon_undo); undo.setEnabled(true); } MenuItem redo = menu.findItem(R.id.menu_redo); if (formulaEditorEditText == null || !formulaEditorEditText.getHistory().redoIsPossible()) { redo.setIcon(R.drawable.icon_redo_disabled); redo.setEnabled(false); } else { redo.setIcon(R.drawable.icon_redo); redo.setEnabled(true); } menu.findItem(R.id.menu_undo).setVisible(true); menu.findItem(R.id.menu_redo).setVisible(true); getActivity().getActionBar().setDisplayShowTitleEnabled(true); getActivity().getActionBar().setTitle(getString(R.string.formula_editor_title)); super.onPrepareOptionsMenu(menu); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_formulaeditor, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: exitFormulaEditorFragment(); return true; case R.id.menu_undo: formulaEditorEditText.undo(); break; case R.id.menu_redo: formulaEditorEditText.redo(); break; } updateButtonsOnKeyboardAndInvalidateOptionsMenu(); return super.onOptionsItemSelected(item); } private void setInputFormula(Brick.BrickField brickField, int mode) { switch (mode) { case SET_FORMULA_ON_CREATE_VIEW: formulaEditorEditText.enterNewFormula(currentFormula.getInternFormulaState()); currentFormula.highlightTextField(brickView); refreshFormulaPreviewString(); break; case SET_FORMULA_ON_SWITCH_EDIT_TEXT: Formula newFormula = clonedFormulaBrick.getFormulaWithBrickField(brickField); if (currentFormula == newFormula && formulaEditorEditText.hasChanges()) { formulaEditorEditText.quickSelect(); break; } if (formulaEditorEditText.hasChanges()) { confirmSwitchEditTextTimeStamp[0] = confirmSwitchEditTextTimeStamp[1]; confirmSwitchEditTextTimeStamp[1] = System.currentTimeMillis(); confirmSwitchEditTextCounter++; if (!saveFormulaIfPossible()) { return; } } MenuItem undo = currentMenu.findItem(R.id.menu_undo); if (undo != null) { undo.setIcon(R.drawable.icon_undo_disabled); undo.setEnabled(false); } MenuItem redo = currentMenu.findItem(R.id.menu_redo); redo.setIcon(R.drawable.icon_redo_disabled); redo.setEnabled(false); formulaEditorEditText.endEdit(); currentBrickField = brickField; currentFormula = newFormula; formulaEditorEditText.enterNewFormula(newFormula.getInternFormulaState()); refreshFormulaPreviewString(); break; default: break; } } public boolean saveFormulaIfPossible() { InternFormulaParser formulaToParse = formulaEditorEditText.getFormulaParser(); FormulaElement formulaParseTree = formulaToParse.parseFormula(); switch (formulaToParse.getErrorTokenIndex()) { case PARSER_OK: currentFormula.setRoot(formulaParseTree); if (onFormulaChangedListener != null) { onFormulaChangedListener.onFormulaChanged(formulaBrick, currentBrickField, currentFormula); } if (formulaEditorBrick != null) { currentFormula.refreshTextField(brickView); } formulaEditorEditText.formulaSaved(); showToast(R.string.formula_editor_changes_saved, false); return true; case PARSER_STACK_OVERFLOW: return checkReturnWithoutSaving(PARSER_STACK_OVERFLOW); default: formulaEditorEditText.setParseErrorCursorAndSelection(); return checkReturnWithoutSaving(PARSER_INPUT_SYNTAX_ERROR); } } private boolean checkReturnWithoutSaving(int errorType) { if ((System.currentTimeMillis() <= confirmSwitchEditTextTimeStamp[0] + TIME_WINDOW) && (confirmSwitchEditTextCounter > 1)) { confirmSwitchEditTextTimeStamp[0] = 0; confirmSwitchEditTextTimeStamp[1] = 0; confirmSwitchEditTextCounter = 0; currentFormula.setDisplayText(null); showToast(R.string.formula_editor_changes_discarded, false); return true; } else { switch (errorType) { case PARSER_INPUT_SYNTAX_ERROR: showToast(R.string.formula_editor_parse_fail, true); break; case PARSER_STACK_OVERFLOW: showToast(R.string.formula_editor_parse_fail_formula_too_long, true); break; } return false; } } /* * TODO Remove Toasts from this class and replace them with something useful * This is a hack more than anything else. We shouldn't use Toasts if we're going to change the message all the time */ private void showToast(int resourceId, boolean error) { if (error) { ToastUtil.showError(getActivity().getApplicationContext(), resourceId); } else { ToastUtil.showSuccess(getActivity().getApplicationContext(), resourceId); } } @Override public boolean onKey(View view, int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: exitFormulaEditorFragment(); return true; } return false; } private void exitFormulaEditorFragment() { if (formulaEditorEditText.hasChanges()) { AlertDialog.Builder builder = new CustomAlertDialogBuilder(getActivity()); builder.setTitle(R.string.formula_editor_discard_changes_dialog_title) .setMessage(R.string.formula_editor_discard_changes_dialog_message) .setNegativeButton(R.string.no, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { showToast(R.string.formula_editor_changes_discarded, false); currentFormula.setDisplayText(null); onUserDismiss(); } }) .setPositiveButton(R.string.yes, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (saveFormulaIfPossible()) { onUserDismiss(); } } }).create().show(); } else { onUserDismiss(); } } private void endFormulaEditor() { if (formulaEditorEditText.hasChanges()) { if (saveFormulaIfPossible()) { updateUserBricksIfNecessary(); onUserDismiss(); } } else { onUserDismiss(); } } private static void updateUserBricksIfNecessary() { if (formulaBrick instanceof UserBrickParameter) { UserBrick userBrick = ((UserBrickParameter) formulaBrick).getParent(); userBrick.updateUserBrickParametersAndVariables(); } } public void refreshFormulaPreviewString() { refreshFormulaPreviewString(formulaEditorEditText.getStringFromInternFormula()); } public void refreshFormulaPreviewString(String newString) { currentFormula.setDisplayText(newString); updateBrickView(); currentFormula.refreshTextField(brickView, newString); if (!showCustomView) { currentFormula.highlightTextField(brickView); } } private void showFormularEditorCategorylistFragment(String tag, int actionbarResId) { FragmentManager fragmentManager = ((Activity) context).getFragmentManager(); Fragment fragment = fragmentManager.findFragmentByTag(tag); if (fragment == null) { fragment = new FormulaEditorCategoryListFragment(); Bundle bundle = new Bundle(); bundle.putString(FormulaEditorCategoryListFragment.ACTION_BAR_TITLE_BUNDLE_ARGUMENT, context.getString(actionbarResId)); bundle.putString(FormulaEditorCategoryListFragment.FRAGMENT_TAG_BUNDLE_ARGUMENT, tag); fragment.setArguments(bundle); fragmentManager.beginTransaction().add(R.id.fragment_container, fragment, tag).commit(); } ((FormulaEditorCategoryListFragment) fragment).showFragment(context); } private void showFormulaEditorDataFragment(String tag, int actionbarResId) { FragmentManager fragmentManager = ((Activity) context).getFragmentManager(); Fragment fragment = fragmentManager.findFragmentByTag(tag); if (fragment == null) { fragment = new FormulaEditorDataFragment(); Bundle bundle = new Bundle(); bundle.putString(FormulaEditorDataFragment.ACTION_BAR_TITLE_BUNDLE_ARGUMENT, context.getString(actionbarResId)); bundle.putString(FormulaEditorDataFragment.FRAGMENT_TAG_BUNDLE_ARGUMENT, tag); fragment.setArguments(bundle); fragmentManager.beginTransaction().add(R.id.fragment_container, fragment, tag).commit(); } ((FormulaEditorDataFragment) fragment).setAddButtonListener(getActivity()); ((FormulaEditorDataFragment) fragment).showFragment(context); } @SuppressWarnings("deprecation") @Override public void onGlobalLayout() { fragmentView.getViewTreeObserver().removeGlobalOnLayoutListener(this); Rect brickRect = new Rect(); Rect keyboardRec = new Rect(); formulaEditorBrick.getGlobalVisibleRect(brickRect); formulaEditorKeyboard.getGlobalVisibleRect(keyboardRec); } public void addResourceToActiveFormula(int resource) { formulaEditorEditText.handleKeyEvent(resource, ""); if (resource == R.string.formula_editor_function_collides_with_edge || resource == R.string .formula_editor_function_touched) { ProjectManager.getInstance().getCurrentSprite().createCollisionPolygons(); } } public void addUserListToActiveFormula(String userListName) { formulaEditorEditText.handleKeyEvent(InternFormulaKeyboardAdapter.FORMULA_EDITOR_USER_LIST_RESOURCE_ID, userListName); } public void addUserVariableToActiveFormula(String userVariableName) { formulaEditorEditText.handleKeyEvent(InternFormulaKeyboardAdapter.FORMULA_EDITOR_USER_VARIABLE_RESOURCE_ID, userVariableName); } public void addCollideFormulaToActiveFormula(String spriteName) { formulaEditorEditText.handleKeyEvent(InternFormulaKeyboardAdapter.FORMULA_EDITOR_COLLIDE_RESOURCE_ID, spriteName); } public void addStringToActiveFormula(String string) { formulaEditorEditText.handleKeyEvent(R.id.formula_editor_keyboard_string, string); } public String getSelectedFormulaText() { return formulaEditorEditText.getSelectedTextFromInternFormula(); } public void overrideSelectedText(String string) { formulaEditorEditText.overrideSelectedText(string); } private class VariableOrUserListDeletedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(ScriptActivity.ACTION_VARIABLE_DELETED) || intent.getAction().equals(ScriptActivity.ACTION_USERLIST_DELETED)) { updateBrickView(); } } } @Override public void onPause() { super.onPause(); if (variableOrUserListDeletedReceiver != null) { getActivity().unregisterReceiver(variableOrUserListDeletedReceiver); } } @Override public void onResume() { super.onResume(); if (variableOrUserListDeletedReceiver == null) { variableOrUserListDeletedReceiver = new VariableOrUserListDeletedReceiver(); } IntentFilter filterVariableDeleted = new IntentFilter(ScriptActivity.ACTION_VARIABLE_DELETED); BottomBar.hideBottomBar(getActivity()); filterVariableDeleted.addAction(ScriptActivity.ACTION_USERLIST_DELETED); getActivity().registerReceiver(variableOrUserListDeletedReceiver, filterVariableDeleted); } public void updateButtonsOnKeyboardAndInvalidateOptionsMenu() { getActivity().invalidateOptionsMenu(); ImageButton backspaceOnKeyboard = (ImageButton) getActivity().findViewById(R.id.formula_editor_keyboard_delete); if (!formulaEditorEditText.isThereSomethingToDelete()) { backspaceOnKeyboard.setAlpha(255 / 3); backspaceOnKeyboard.setEnabled(false); } else { backspaceOnKeyboard.setAlpha(255); backspaceOnKeyboard.setEnabled(true); } } }