/* * 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; import android.content.Context; import android.content.res.Resources; import android.os.Build; import com.thoughtworks.xstream.annotations.XStreamAlias; import org.catrobat.catroid.R; import org.catrobat.catroid.common.Constants; import org.catrobat.catroid.common.MessageContainer; import org.catrobat.catroid.common.ScreenModes; import org.catrobat.catroid.common.ScreenValues; import org.catrobat.catroid.content.bricks.Brick; import org.catrobat.catroid.devices.mindstorms.ev3.sensors.EV3Sensor; import org.catrobat.catroid.devices.mindstorms.nxt.sensors.NXTSensor; import org.catrobat.catroid.formulaeditor.BaseDataContainer; import org.catrobat.catroid.formulaeditor.DataContainer; import org.catrobat.catroid.formulaeditor.UserList; import org.catrobat.catroid.formulaeditor.UserVariable; import org.catrobat.catroid.io.XStreamFieldKeyOrder; import org.catrobat.catroid.physics.content.ActionPhysicsFactory; import org.catrobat.catroid.stage.StageActivity; import org.catrobat.catroid.ui.SettingsActivity; import org.catrobat.catroid.utils.UtilUi; import org.catrobat.catroid.utils.Utils; import java.io.File; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @XStreamAlias("program") // Remove checkstyle disable when https://github.com/checkstyle/checkstyle/issues/1349 is fixed // CHECKSTYLE DISABLE IndentationCheck FOR 7 LINES @XStreamFieldKeyOrder({ "header", "settings", "scenes", "programVariableList", "programListOfLists" }) public class Project implements Serializable { private static final long serialVersionUID = 1L; @XStreamAlias("header") private XmlHeader xmlHeader = new XmlHeader(); @XStreamAlias("settings") private List<Setting> settings = new ArrayList<>(); @XStreamAlias("programVariableList") private List<UserVariable> projectVariables = new ArrayList<>(); @XStreamAlias("programListOfLists") private List<UserList> projectLists = new ArrayList<>(); @XStreamAlias("scenes") private List<Scene> sceneList = new ArrayList<>(); public Project(Context context, String name, boolean landscapeMode) { xmlHeader.setProgramName(name); xmlHeader.setDescription(""); xmlHeader.setlandscapeMode(landscapeMode); if (ScreenValues.SCREEN_HEIGHT == 0 || ScreenValues.SCREEN_WIDTH == 0) { UtilUi.updateScreenWidthAndHeight(context); } if (landscapeMode) { ifPortraitSwitchWidthAndHeight(); } else { ifLandscapeSwitchWidthAndHeight(); } xmlHeader.virtualScreenWidth = ScreenValues.SCREEN_WIDTH; xmlHeader.virtualScreenHeight = ScreenValues.SCREEN_HEIGHT; setDeviceData(context); MessageContainer.clear(); //This is used for tests if (context == null) { //Because in test project we can't find the string sceneList.add(new Scene(context, "Scene 1", this)); } else { sceneList.add(new Scene(context, context.getString(R.string.default_scene_name, 1), this)); } xmlHeader.scenesEnabled = true; } public Project(Context context, String name) { this(context, name, false); } public Project(SupportProject oldProject, Context context) { xmlHeader = oldProject.xmlHeader; settings = oldProject.settings; projectVariables = oldProject.dataContainer.projectVariables; projectLists = oldProject.dataContainer.projectLists; Scene scene; try { scene = new Scene(context, context.getString(R.string.default_scene_name, 1), this); } catch (Resources.NotFoundException e) { //Because in test project we can't find the string scene = new Scene(context, "Scene 1", this); } DataContainer container = new DataContainer(this); removeInvalidVariablesAndLists(oldProject.dataContainer); container.setSpriteVariablesForSupportContainer(oldProject.dataContainer); scene.setDataContainer(container); scene.setSpriteList(oldProject.spriteList); sceneList.add(scene); } public void removeInvalidVariablesAndLists(BaseDataContainer dataContainer) { if (dataContainer == null) { return; } if (dataContainer.spriteListOfLists != null) { Iterator listIterator = dataContainer.spriteListOfLists.keySet().iterator(); while (listIterator.hasNext()) { Sprite sprite = (Sprite) listIterator.next(); if (sprite == null) { listIterator.remove(); } } } if (dataContainer.spriteVariables != null) { Iterator variablesIterator = dataContainer.spriteVariables.keySet().iterator(); while (variablesIterator.hasNext()) { Sprite sprite = (Sprite) variablesIterator.next(); if (sprite == null) { variablesIterator.remove(); } } } } public List<Scene> getSceneList() { return sceneList; } public List<String> getSceneOrder() { List<String> sceneOrder = new ArrayList<>(); for (Scene scene : sceneList) { sceneOrder.add(scene.getName()); } return sceneOrder; } public void setSceneList(List<Scene> scenes) { sceneList = scenes; } public void addScene(Scene scene) { sceneList.add(scene); } public void removeScene(Scene scene) { sceneList.remove(scene); } public Scene getDefaultScene() { return sceneList.get(0); } public List<UserVariable> getProjectVariables() { if (projectVariables == null) { projectVariables = new ArrayList<>(); } return projectVariables; } public List<UserList> getProjectLists() { if (projectLists == null) { projectLists = new ArrayList<>(); } return projectLists; } public UserVariable getProjectVariableWithName(String name) { for (UserVariable variable : getProjectVariables()) { if (name.equals(variable.getName())) { return variable; } } return null; } public UserList getProjectListWithName(String name) { for (UserList list : getProjectLists()) { if (name.equals(list.getName())) { return list; } } return null; } private void ifLandscapeSwitchWidthAndHeight() { if (ScreenValues.SCREEN_WIDTH > ScreenValues.SCREEN_HEIGHT) { int tmp = ScreenValues.SCREEN_HEIGHT; ScreenValues.SCREEN_HEIGHT = ScreenValues.SCREEN_WIDTH; ScreenValues.SCREEN_WIDTH = tmp; } } private void ifPortraitSwitchWidthAndHeight() { if (ScreenValues.SCREEN_WIDTH < ScreenValues.SCREEN_HEIGHT) { int tmp = ScreenValues.SCREEN_HEIGHT; ScreenValues.SCREEN_HEIGHT = ScreenValues.SCREEN_WIDTH; ScreenValues.SCREEN_WIDTH = tmp; } } public boolean isScenesEnabled() { return sceneList.size() > 1; } public void setName(String name) { xmlHeader.setProgramName(name); } public List<Sprite> getSpriteListWithClones() { if (StageActivity.stageListener != null) { return StageActivity.stageListener.getSpritesFromStage(); } else { // e.g. for ActionTests there is no Stage, only use sprites from Project return getDefaultScene().getSpriteList(); } } public String getName() { return xmlHeader.getProgramName(); } public void setDescription(String description) { xmlHeader.setDescription(description); } public String getDescription() { return xmlHeader.getDescription(); } public void setScreenMode(ScreenModes screenMode) { xmlHeader.setScreenMode(screenMode); } public ScreenModes getScreenMode() { return xmlHeader.getScreenMode(); } public float getCatrobatLanguageVersion() { return xmlHeader.getCatrobatLanguageVersion(); } public XmlHeader getXmlHeader() { return this.xmlHeader; } public int getRequiredResources() { int resources = Brick.NO_RESOURCES; ActionFactory physicsActionFactory = new ActionPhysicsFactory(); ActionFactory actionFactory = new ActionFactory(); for (Scene scene : sceneList) { for (Sprite sprite : scene.getSpriteList()) { int tempResources = sprite.getRequiredResources(); if ((tempResources & Brick.PHYSICS) != 0) { sprite.setActionFactory(physicsActionFactory); tempResources &= ~Brick.PHYSICS; } else { sprite.setActionFactory(actionFactory); } resources |= tempResources; } } return resources; } // this method should be removed by the nex refactoring // (used only in tests) public void setCatrobatLanguageVersion(float catrobatLanguageVersion) { xmlHeader.setCatrobatLanguageVersion(catrobatLanguageVersion); } public void setDeviceData(Context context) { // TODO add other header values xmlHeader.setPlatform(Constants.PLATFORM_NAME); xmlHeader.setPlatformVersion((double) Build.VERSION.SDK_INT); xmlHeader.setDeviceName(Build.MODEL); xmlHeader.setCatrobatLanguageVersion(Constants.CURRENT_CATROBAT_LANGUAGE_VERSION); xmlHeader.setApplicationBuildName(Constants.APPLICATION_BUILD_NAME); xmlHeader.setApplicationBuildNumber(Constants.APPLICATION_BUILD_NUMBER); if (context == null) { xmlHeader.setApplicationVersion("unknown"); xmlHeader.setApplicationName("unknown"); } else { xmlHeader.setApplicationVersion(Utils.getVersionName(context)); xmlHeader.setApplicationName(context.getString(R.string.app_name)); } } public void setTags(List<String> tags) { xmlHeader.setTags(tags); } // default constructor for XMLParser public Project() { } public List<Setting> getSettings() { return settings; } public Scene getSceneByName(String name) { for (Scene scene : sceneList) { if (scene.getName().equals(name)) { return scene; } } return null; } public boolean containsScene(Scene scene) { return getSceneOrder().contains(scene.getName()); } public boolean manualScreenshotExists(String manualScreenshotName) { String path = Utils.buildProjectPath(getName()) + "/" + manualScreenshotName; File manualScreenShot = new File(path); if (manualScreenShot.exists()) { return false; } return true; } public void setXmlHeader(XmlHeader xmlHeader) { this.xmlHeader = xmlHeader; } public void saveLegoNXTSettingsToProject(Context context) { if (context == null) { return; } if ((getRequiredResources() & Brick.BLUETOOTH_LEGO_NXT) == 0) { for (Object setting : settings.toArray()) { if (setting instanceof LegoNXTSetting) { settings.remove(setting); return; } } return; } NXTSensor.Sensor[] sensorMapping = SettingsActivity.getLegoMindstormsNXTSensorMapping(context); for (Setting setting : settings) { if (setting instanceof LegoNXTSetting) { ((LegoNXTSetting) setting).updateMapping(sensorMapping); return; } } Setting mapping = new LegoNXTSetting(sensorMapping); settings.add(mapping); } public void saveLegoEV3SettingsToProject(Context context) { if (context == null) { return; } if ((getRequiredResources() & Brick.BLUETOOTH_LEGO_EV3) == 0) { for (Object setting : settings.toArray()) { if (setting instanceof LegoEV3Setting) { settings.remove(setting); return; } } return; } EV3Sensor.Sensor[] sensorMapping = SettingsActivity.getLegoMindstormsEV3SensorMapping(context); for (Setting setting : settings) { if (setting instanceof LegoEV3Setting) { ((LegoEV3Setting) setting).updateMapping(sensorMapping); return; } } Setting mapping = new LegoEV3Setting(sensorMapping); settings.add(mapping); } public void loadLegoNXTSettingsFromProject(Context context) { if (context == null) { return; } for (Setting setting : settings) { if (setting instanceof LegoNXTSetting) { SettingsActivity.enableLegoMindstormsNXTBricks(context); SettingsActivity.setLegoMindstormsNXTSensorMapping(context, ((LegoNXTSetting) setting).getSensorMapping()); return; } } } public void loadLegoEV3SettingsFromProject(Context context) { if (context == null) { return; } for (Setting setting : settings) { if (setting instanceof LegoEV3Setting) { SettingsActivity.enableLegoMindstormsEV3Bricks(context); SettingsActivity.setLegoMindstormsEV3SensorMapping(context, ((LegoEV3Setting) setting).getSensorMapping()); return; } } } public void refreshSpriteReferences() { for (Scene scene : sceneList) { scene.refreshSpriteReferences(); } } public void updateCollisionFormulasToVersion(float catroidLanguageVersion) { for (Scene scene : sceneList) { for (Sprite sprite : scene.getSpriteList()) { sprite.updateCollisionFormulasToVersion(catroidLanguageVersion); } } } }