Unverified Commit 160f16c0 authored by hal's avatar hal Committed by Jeffrey I. Schiller

Add the “ShowListsAsJson” Property

When set this property causes lists to be displayed in JSON notation
rather then Lisp notation. Its default value is “false” so current
projects continue to work and new projects will still use Lisp
format. This can be changed in the future once the Companion that
supports ShowListsAsJson is widely deployed.

Change-Id: I2e6b25c32d27377685eb8111f44536479e7c55b7
parent c976f01e
......@@ -3020,6 +3020,10 @@ public interface OdeMessages extends Messages {
@Description("")
String SizingProperties();
@DefaultMessage("ShowListsAsJson")
@Description("")
String ShowListsAsJsonProperties();
@DefaultMessage("Visible")
@Description("")
String VisibleProperties();
......
......@@ -170,6 +170,8 @@ public final class MockForm extends MockContainer {
private static final String PROPERTY_NAME_VNAME = "VersionName";
private static final String PROPERTY_NAME_ANAME = "AppName";
private static final String PROPERTY_NAME_SIZING = "Sizing"; // Don't show except on screen1
// Don't show except on screen1
private static final String PROPERTY_NAME_SHOW_LISTS_AS_JSON = "ShowListsAsJson";
// Form UI components
AbsolutePanel formWidget;
......@@ -417,6 +419,11 @@ public final class MockForm extends MockContainer {
return editor.isScreen1();
}
if (propertyName.equals(PROPERTY_NAME_SHOW_LISTS_AS_JSON)) {
// The ShowListsAsJson property actually applies to the application and is only visible on Screen1.
return editor.isScreen1();
}
return super.isPropertyVisible(propertyName);
}
......@@ -519,6 +526,17 @@ public final class MockForm extends MockContainer {
}
}
private void setShowListsAsJsonProperty(String asJson) {
// This property actually applies to the application and is only visible on
// Screen1. When we load a form that is not Screen1, this method will be called with the
// default value for CompatibilityProperty (false). We need to ignore that.
if (editor.isScreen1()) {
editor.getProjectEditor().changeProjectSettingsProperty(
SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS,
SettingsConstants.YOUNG_ANDROID_SETTINGS_SHOW_LISTS_AS_JSON, asJson);
}
}
private void setANameProperty(String aname) {
// The AppName property actually applies to the application and is only visible on Screen1.
// When we load a form that is not Screen1, this method will be called with the default value
......@@ -732,6 +750,8 @@ public final class MockForm extends MockContainer {
setVNameProperty(newValue);
} else if (propertyName.equals(PROPERTY_NAME_ANAME)) {
setANameProperty(newValue);
} else if (propertyName.equals(PROPERTY_NAME_SHOW_LISTS_AS_JSON)) {
setShowListsAsJsonProperty(newValue);
} else if (propertyName.equals(PROPERTY_NAME_HORIZONTAL_ALIGNMENT)) {
myLayout.setHAlignmentFlags(newValue);
refreshForm();
......@@ -761,15 +781,20 @@ public final class MockForm extends MockContainer {
@Override
public EditableProperties getProperties() {
// Before we return the Properties object, we make sure that the
// Sizing property has the value from the project's properties
// this is because Sizing is per project, not per Screen(Form)
// We only have to do this on screens other then screen1 because
// screen1's value is definitive.
if(!editor.isScreen1()) {
// Sizing and ShowListsAsJson properties have the value from the
// project's properties this is because these are per project, not
// per Screen(Form) We only have to do this on screens other then
// screen1 because screen1's value is definitive.
if (!editor.isScreen1()) {
properties.changePropertyValue(SettingsConstants.YOUNG_ANDROID_SETTINGS_SIZING,
editor.getProjectEditor().getProjectSettingsProperty(
SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS,
SettingsConstants.YOUNG_ANDROID_SETTINGS_SIZING));
// new code to test
properties.changePropertyValue(SettingsConstants.YOUNG_ANDROID_SETTINGS_SHOW_LISTS_AS_JSON,
editor.getProjectEditor().getProjectSettingsProperty(
SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS,
SettingsConstants.YOUNG_ANDROID_SETTINGS_SHOW_LISTS_AS_JSON));
}
return properties;
}
......
......@@ -48,5 +48,9 @@ public final class YoungAndroidSettings extends Settings {
addProperty(new EditableProperty(this,
SettingsConstants.YOUNG_ANDROID_SETTINGS_SIZING, "Fixed",
EditableProperty.TYPE_INVISIBLE));
addProperty(new EditableProperty(this,
SettingsConstants.YOUNG_ANDROID_SETTINGS_SHOW_LISTS_AS_JSON, "false",
EditableProperty.TYPE_INVISIBLE));
}
}
......@@ -914,6 +914,11 @@ public final class YoungAndroidFormUpgrader {
srcCompVersion = 19;
}
if (srcCompVersion < 20) {
// The ShowistsAsJson Property was added.
srcCompVersion = 20;
}
return srcCompVersion;
}
......
......@@ -102,7 +102,7 @@ public final class FileImporterImpl implements FileImporter {
// so that it contains the correct entries for "main" and "name", which are dependent on
// the projectName and qualifiedFormName.
String content = YoungAndroidProjectService.getProjectPropertiesFileContents(
projectName, qualifiedFormName, null, null, null, null, null, null);
projectName, qualifiedFormName, null, null, null, null, null, null, null);
project.addTextFile(new TextFile(fileName, content));
isProjectArchive = true;
......@@ -149,7 +149,7 @@ public final class FileImporterImpl implements FileImporter {
if (projectHistory != null) {
project.setProjectHistory(projectHistory);
}
String settings = YoungAndroidProjectService.getProjectSettings(null, null, null, null, null, null);
String settings = YoungAndroidProjectService.getProjectSettings(null, null, null, null, null, null, null);
long projectId = storageIo.createProject(userId, project, settings);
return storageIo.getUserProject(userId, projectId);
}
......
......@@ -128,13 +128,14 @@ public final class YoungAndroidProjectService extends CommonProjectService {
* Returns project settings that can be used when creating a new project.
*/
public static String getProjectSettings(String icon, String vCode, String vName,
String useslocation, String aName, String sizing) {
String useslocation, String aName, String sizing, String showListsAsJson) {
icon = Strings.nullToEmpty(icon);
vCode = Strings.nullToEmpty(vCode);
vName = Strings.nullToEmpty(vName);
useslocation = Strings.nullToEmpty(useslocation);
sizing = Strings.nullToEmpty(sizing);
aName = Strings.nullToEmpty(aName);
showListsAsJson = Strings.nullToEmpty(showListsAsJson);
return "{\"" + SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS + "\":{" +
"\"" + SettingsConstants.YOUNG_ANDROID_SETTINGS_ICON + "\":\"" + icon +
"\",\"" + SettingsConstants.YOUNG_ANDROID_SETTINGS_VERSION_CODE + "\":\"" + vCode +
......@@ -142,6 +143,7 @@ public final class YoungAndroidProjectService extends CommonProjectService {
"\",\"" + SettingsConstants.YOUNG_ANDROID_SETTINGS_USES_LOCATION + "\":\"" + useslocation +
"\",\"" + SettingsConstants.YOUNG_ANDROID_SETTINGS_APP_NAME + "\":\"" + aName +
"\",\"" + SettingsConstants.YOUNG_ANDROID_SETTINGS_SIZING + "\":\"" + sizing +
"\",\"" + SettingsConstants.YOUNG_ANDROID_SETTINGS_SHOW_LISTS_AS_JSON + "\":\"" + showListsAsJson +
"\"}}";
}
......@@ -156,7 +158,7 @@ public final class YoungAndroidProjectService extends CommonProjectService {
* @param vname the version name
*/
public static String getProjectPropertiesFileContents(String projectName, String qualifiedName,
String icon, String vcode, String vname, String useslocation, String aname, String sizing) {
String icon, String vcode, String vname, String useslocation, String aname, String sizing, String showListsAsJson) {
String contents = "main=" + qualifiedName + "\n" +
"name=" + projectName + '\n' +
"assets=../" + ASSETS_FOLDER + "\n" +
......@@ -180,6 +182,9 @@ public final class YoungAndroidProjectService extends CommonProjectService {
if (sizing != null && !sizing.isEmpty()) {
contents += "sizing=" + sizing + "\n";
}
if (showListsAsJson != null && !showListsAsJson.isEmpty()) {
contents += "showlistsasjson=" + showListsAsJson + "\n";
}
return contents;
}
......@@ -246,6 +251,9 @@ public final class YoungAndroidProjectService extends CommonProjectService {
String newSizing = Strings.nullToEmpty(settings.getSetting(
SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS,
SettingsConstants.YOUNG_ANDROID_SETTINGS_SIZING));
String newShowListsAsJson = Strings.nullToEmpty(settings.getSetting(
SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS,
SettingsConstants.YOUNG_ANDROID_SETTINGS_SHOW_LISTS_AS_JSON));
String newAName = Strings.nullToEmpty(settings.getSetting(
SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS,
SettingsConstants.YOUNG_ANDROID_SETTINGS_APP_NAME));
......@@ -267,15 +275,17 @@ public final class YoungAndroidProjectService extends CommonProjectService {
String oldUsesLocation = Strings.nullToEmpty(properties.getProperty("useslocation"));
String oldSizing = Strings.nullToEmpty(properties.getProperty("sizing"));
String oldAName = Strings.nullToEmpty(properties.getProperty("aname"));
String oldShowListsAsJson = Strings.nullToEmpty(properties.getProperty("showlistsasjson"));
if (!newIcon.equals(oldIcon) || !newVCode.equals(oldVCode) || !newVName.equals(oldVName)
|| !newUsesLocation.equals(oldUsesLocation) ||
!newAName.equals(oldAName) || !newSizing.equals(oldSizing)) {
!newAName.equals(oldAName) || !newSizing.equals(oldSizing) ||
!newShowListsAsJson.equals(oldShowListsAsJson)) {
// Recreate the project.properties and upload it to storageIo.
String projectName = properties.getProperty("name");
String qualifiedName = properties.getProperty("main");
String newContent = getProjectPropertiesFileContents(projectName, qualifiedName, newIcon,
newVCode, newVName, newUsesLocation, newAName, newSizing);
newVCode, newVName, newUsesLocation, newAName, newSizing, newShowListsAsJson);
storageIo.uploadFileForce(projectId, PROJECT_PROPERTIES_FILE_NAME, userId,
newContent, StorageUtil.DEFAULT_CHARSET);
}
......@@ -294,7 +304,7 @@ public final class YoungAndroidProjectService extends CommonProjectService {
String propertiesFileName = PROJECT_PROPERTIES_FILE_NAME;
String propertiesFileContents = getProjectPropertiesFileContents(projectName,
qualifiedFormName, null, null, null, null, null, null);
qualifiedFormName, null, null, null, null, null, null, null);
String formFileName = YoungAndroidFormNode.getFormFileId(qualifiedFormName);
String formFileContents = getInitialFormPropertiesFileContents(qualifiedFormName);
......@@ -314,7 +324,7 @@ public final class YoungAndroidProjectService extends CommonProjectService {
project.addTextFile(new TextFile(yailFileName, yailFileContents));
// Create new project
return storageIo.createProject(userId, project, getProjectSettings("", "1", "1.0", "false", projectName, "Fixed"));
return storageIo.createProject(userId, project, getProjectSettings("", "1", "1.0", "false", projectName, "Fixed", "false"));
}
@Override
......@@ -341,6 +351,9 @@ public final class YoungAndroidProjectService extends CommonProjectService {
String sizing = oldSettings.getSetting(
SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS,
SettingsConstants.YOUNG_ANDROID_SETTINGS_SIZING);
String showListsAsJson = oldSettings.getSetting(
SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS,
SettingsConstants.YOUNG_ANDROID_SETTINGS_SHOW_LISTS_AS_JSON);
Project newProject = new Project(newName);
newProject.setProjectType(YoungAndroidProjectNode.YOUNG_ANDROID_PROJECT_TYPE);
......@@ -359,7 +372,8 @@ public final class YoungAndroidProjectService extends CommonProjectService {
// name and qualified name.
String qualifiedFormName = StringUtils.getQualifiedFormName(
storageIo.getUser(userId).getUserEmail(), newName);
newContents = getProjectPropertiesFileContents(newName, qualifiedFormName, icon, vcode, vname, useslocation, aname, sizing);
newContents = getProjectPropertiesFileContents(newName, qualifiedFormName, icon, vcode,
vname, useslocation, aname, sizing, showListsAsJson);
} else {
// This is some file other than the project properties file.
// oldSourceFileName may contain the old project name as a path segment, surrounded by /.
......@@ -383,7 +397,7 @@ public final class YoungAndroidProjectService extends CommonProjectService {
// Create the new project and return the new project's id.
return storageIo.createProject(userId, newProject, getProjectSettings(icon, vcode, vname,
useslocation, aname, sizing));
useslocation, aname, sizing, showListsAsJson));
}
@Override
......
......@@ -49,4 +49,5 @@ public class SettingsConstants {
public static final String YOUNG_ANDROID_SETTINGS_USES_LOCATION = "UsesLocation";
public static final String YOUNG_ANDROID_SETTINGS_SIZING = "Sizing";
public static final String YOUNG_ANDROID_SETTINGS_APP_NAME = "AppName";
public static final String YOUNG_ANDROID_SETTINGS_SHOW_LISTS_AS_JSON = "ShowListsAsJson";
}
......@@ -343,7 +343,8 @@ public class ProjectServiceTest {
"versionname=1.0\n" +
"useslocation=false\n" +
"aname=Project1\n" +
"sizing=Fixed\n");
"sizing=Fixed\n" +
"showlistsasjson=false\n");
expectedYaFiles2.put("src/com/domain/noname/Project2/Screen1.scm",
YOUNG_ANDROID_PROJECT_SCM_SOURCE);
assertEquals(expectedYaFiles2, getTextFiles(USER_ID_ONE, yaProject2));
......@@ -490,7 +491,8 @@ public class ProjectServiceTest {
SettingsConstants.YOUNG_ANDROID_SETTINGS_VERSION_NAME + "\":\"1.0\",\"" +
SettingsConstants.YOUNG_ANDROID_SETTINGS_USES_LOCATION + "\":\"false\",\"" +
SettingsConstants.YOUNG_ANDROID_SETTINGS_APP_NAME + "\":\"Project1\",\"" +
SettingsConstants.YOUNG_ANDROID_SETTINGS_SIZING + "\":\"Fixed\"}}",
SettingsConstants.YOUNG_ANDROID_SETTINGS_SIZING + "\":\"Fixed\",\"" +
SettingsConstants.YOUNG_ANDROID_SETTINGS_SHOW_LISTS_AS_JSON + "\":\"false\"}}",
loadedSettings);
String storedSettings =
......
......@@ -2049,13 +2049,19 @@ Blockly.Versioning.AllUpgradeMaps =
// - Screen.CompatibilityMode property was added no block needs to be changed.
17: "noUpgrade",
// FOR FORM_COMPONENT_VERSION 18:
// Screen.CompatibililtyMode replaced with Screen.Sizing no blocks need to be
// changed.
18: "noUpgrade",
// For FORM_COMPONENT_VERSION 19:
// - The Screen1.HideKeyboard method was added and no block needs to be changed.
19: "noUpgrade"
19: "noUpgrade",
// For FORM_COMPONENT_VERSION 20:
// - The Screen1.ShowListsAsJson property was added and no block needs to be changed.
20: "noUpgrade"
}, // End Screen
......
......@@ -23,6 +23,11 @@
(define *this-is-the-repl* #f)
;;; If set we avoid calling to java components such as Form
;;; because we are running in a test environment that is not
;;; inside a phone, so components are not defined
(define *testing* #f)
(define (android-log message)
(when *debug* (android.util.Log:i "YAIL" message)))
......@@ -1107,14 +1112,10 @@
(let loop ((result "") (rest-elements bracketed))
(if (null? rest-elements)
result
(loop (string-append result " " (car rest-elements))
(loop (string-append result ", " (car rest-elements))
(cdr rest-elements))))))
;;(define (show-arglist-no-parens args)
;; (let ((s (get-display-representation args)))
;; (substring s 1 (- (string-length s) 1))))
;;; Coerce the list of args to the corresponding list of types
(define (coerce-args procedure-name arglist typelist)
......@@ -1195,6 +1196,11 @@
(or (padded-string->number arg) *non-coercible-value*))
(else *non-coercible-value*)))
(define-syntax use-json-format
(syntax-rules ()
((_)
(if *testing* #t
(*:ShowListsAsJson (SimpleForm:getActiveForm))))))
(define (coerce-to-string arg)
(cond ((eq? arg *the-null-value*) *the-null-value-printed-rep*)
......@@ -1203,8 +1209,11 @@
((boolean? arg) (boolean->string arg))
((yail-list? arg) (coerce-to-string (yail-list->kawa-list arg)))
((list? arg)
(let ((pieces (map coerce-to-string arg)))
(call-with-output-string (lambda (port) (display pieces port)))))
(if (use-json-format)
(let ((pieces (map get-json-display-representation arg)))
(string-append "[" (join-strings pieces ", ") "]"))
(let ((pieces (map coerce-to-string arg)))
(call-with-output-string (lambda (port) (display pieces port))))))
(else (call-with-output-string (lambda (port) (display arg port))))))
;;; This is very similar to coerce-to-string, but is intended for places where we
......@@ -1212,9 +1221,16 @@
;;; be explicity shown in error messages.
;;; This procedure is currently almost completely redundant with coerce-to-string
;;; but it give us flexibility to tailor display for other data types
(define get-display-representation
;; there seems to be a bug in Kawa that makes (/ -1 0) equal to (/ 1 0)
;; which is why this uses 1.0 and -1.0
(lambda (arg)
(if (use-json-format)
(get-json-display-representation arg)
(get-original-display-representation arg))))
(define get-original-display-representation
;;there seems to be a bug in Kawa that makes (/ -1 0) equal to (/ 1 0)
;;which is why this uses 1.0 and -1.0
(let ((+inf (/ 1.0 0))
(-inf (/ -1.0 0)))
(lambda (arg)
......@@ -1235,6 +1251,40 @@
(call-with-output-string (lambda (port) (display pieces port)))))
(else (call-with-output-string (lambda (port) (display arg port))))))))
(define get-json-display-representation
;; there seems to be a bug in Kawa that makes (/ -1 0) equal to (/ 1 0)
;; which is why this uses 1.0 and -1.0
(let ((+inf (/ 1.0 0))
(-inf (/ -1.0 0)))
(lambda (arg)
(cond ((= arg +inf) "+infinity")
((= arg -inf) "-infinity")
((eq? arg *the-null-value*) *the-null-value-printed-rep*)
((symbol? arg)
(symbol->string arg))
((string? arg) (string-append "\"" arg "\""))
((number? arg) (appinventor-number->string arg))
((boolean? arg) (boolean->string arg))
((yail-list? arg) (get-json-display-representation (yail-list->kawa-list arg)))
((list? arg)
(let ((pieces (map get-json-display-representation arg)))
(string-append "[" (join-strings pieces ", ") "]")))
(else (call-with-output-string (lambda (port) (display arg port))))))))
(define (join-strings strings separator)
(cond ((null? strings) "")
((null? (cdr strings)) (car strings))
(else ;; have at least two strings
(apply string-append
(cons (car strings)
(let recur ((strs (cdr strings)))
(if (null? strs)
'()
(cons separator (cons (car strs) (recur (cdr strs)))))))))))
;;;!!! end of replacement
;; Note: This is not general substring replacement. It just replaces one string with another
;; using the replacement table
(define (string-replace original replacement-table)
......@@ -1785,22 +1835,24 @@ list, use the make-yail-list constructor with no arguments.
;;; converts a yail list to a CSV-formatted table and returns the text.
;;; yl should be a YailList, each element of which is a YailList as well.
;;; inner list elements sanitized
;;; inner list elements are sanitized
;;; TODO(hal): do better checking that the input is well-formed
(define (yail-list-to-csv-table yl)
(if (not (yail-list? yl))
(signal-runtime-error "Argument value to \"list to csv table\" must be a list" "Expecting list")
(CsvUtil:toCsvTable (apply make-yail-list (map convert-to-strings (yail-list-contents yl))))))
(CsvUtil:toCsvTable (apply make-yail-list (map convert-to-strings-for-csv (yail-list-contents yl))))))
;;; converts a yail list to a CSV-formatted row and returns the text.
;;; yl should be a YailList
;;; atomic elements sanitized
;;; TODO(hal): do better checking that the input is well-formed
(define (yail-list-to-csv-row yl)
(if (not (yail-list? yl))
(signal-runtime-error "Argument value to \"list to csv row\" must be a list" "Expecting list")
(CsvUtil:toCsvRow (convert-to-strings yl))))
(CsvUtil:toCsvRow (convert-to-strings-for-csv yl))))
;; convert each element of YailList yl to a string and return the resulting YailList
(define (convert-to-strings yl)
(define (convert-to-strings-for-csv yl)
(cond ((yail-list-empty? yl) yl)
((not (yail-list? yl)) (make-yail-list yl))
(else (apply make-yail-list (map coerce-to-string (yail-list-contents yl))))))
......
......@@ -138,7 +138,7 @@ public class YailEvalTest extends TestCase {
assertEquals(6, ((IntNum) scheme.eval(schemeString)).intValue());
schemeString = "(call-yail-primitive string-append (*list-for-runtime* (list 1) \"2\" 3) " +
"'(text text text) \"join\")";
assertEquals("(1)23", scheme.eval(schemeString).toString());
assertEquals("[1]23", scheme.eval(schemeString).toString());
}
public void testDecimalReaderRoundoff() throws Throwable {
......@@ -435,6 +435,7 @@ public class YailEvalTest extends TestCase {
}
/* side-effects */
// these tests assume that we are printing lists using json format
public void testListGroup4() throws Throwable {
String schemeInputString = "(begin " +
"(define list1 (make-yail-list \"a\" \"b\" \"c\" \"d\" ))" +
......@@ -483,7 +484,7 @@ public class YailEvalTest extends TestCase {
"(yail-list-add-to-list! list1)" +
"(coerce-to-string list1)" +
")";
schemeResultString = "(a b c d)";
schemeResultString = "[\"a\", \"b\", \"c\", \"d\"]";
assertEquals(schemeResultString, scheme.eval(schemeInputString).toString());
schemeInputString = "(begin " +
......@@ -491,7 +492,7 @@ public class YailEvalTest extends TestCase {
"(yail-list-add-to-list! list1 1)" +
"(coerce-to-string list1)" +
")";
schemeResultString = "(a 1)";
schemeResultString = "[\"a\", 1]";
assertEquals(schemeResultString, scheme.eval(schemeInputString).toString());
schemeInputString = "(begin " +
......@@ -500,7 +501,7 @@ public class YailEvalTest extends TestCase {
" (*list-for-runtime* x \"hi\" ) '(list any) \"add items to list\") " +
"(coerce-to-string x)" +
")";
schemeResultString = "(a hi)";
schemeResultString = "[\"a\", \"hi\"]";
assertEquals(schemeResultString, scheme.eval(schemeInputString).toString());
schemeInputString = "(begin " +
......@@ -510,7 +511,7 @@ public class YailEvalTest extends TestCase {
" (*list-for-runtime* x y ) '(list any) \"append to list\") " +
"(coerce-to-string x)" +
")";
schemeResultString = "(a ho)";
schemeResultString = "[\"a\", \"ho\"]";
assertEquals(schemeResultString, scheme.eval(schemeInputString).toString());
schemeInputString = "(begin " +
......@@ -523,7 +524,7 @@ public class YailEvalTest extends TestCase {
" (*list-for-runtime* x z ) '(list any) \"append to list\") " +
"(coerce-to-string x)" +
")";
schemeResultString = "(a ho hum)";
schemeResultString = "[\"a\", \"ho\", \"hum\"]";
assertEquals(schemeResultString, scheme.eval(schemeInputString).toString());
schemeInputString = "(begin " +
......@@ -536,7 +537,7 @@ public class YailEvalTest extends TestCase {
" (*list-for-runtime* x z ) '(list any) \"append to list\") " +
"(coerce-to-string y)" +
")";
schemeResultString = "(ho)";
schemeResultString = "[\"ho\"]";
assertEquals(schemeResultString, scheme.eval(schemeInputString).toString());
}
......@@ -1182,10 +1183,9 @@ public class YailEvalTest extends TestCase {
assertFalse((Boolean) scheme.eval("(exact? (yail-divide 2 3))"));
}
public void testConvertToStrings() throws Throwable {
String schemeInputString = "(convert-to-strings (make-yail-list (/ 10 5) 2.0 \"abc\" 123 (list 4 5 6)))";
String schemeExpectedResultString = "(2 2 abc 123 (4 5 6))";
String schemeInputString = "(convert-to-strings-for-csv (make-yail-list (/ 10 5) 2.0 \"abc\" 123 (list 4 5 6)))";
String schemeExpectedResultString = "(2 2 abc 123 [4, 5, 6])";
String schemeActualResult = scheme.eval(schemeInputString).toString();
assertEquals(schemeExpectedResultString, schemeActualResult);
}
......
......@@ -395,8 +395,10 @@ public class YaVersion {
// - LABEL_COMPONENT_VERSION was incremented to 4
// For YOUNG_ANDROID_VERSION 158:
// Added HorizontalScrollArrangement and VerticalScrollArrangement
// For YOUNG_ANDROID_VERSION 159:
// - FORM_COMPONENT_VERSION was incremented to 20
public static final int YOUNG_ANDROID_VERSION = 158;
public static final int YOUNG_ANDROID_VERSION = 159;
// ............................... Blocks Language Version Number ...............................
......@@ -456,6 +458,7 @@ public class YaVersion {
// The number-convert blocks was added
// For BLOCKS_LANGUAGE_VERSION 20:
// - Spelling of "Obsfucate" was corrected to Obfuscate in Text Block
public static final int BLOCKS_LANGUAGE_VERSION = 20;
// ................................. Component Version Numbers ..................................
......@@ -683,7 +686,9 @@ public class YaVersion {
// Sizing property
// For FORM_COMPONENT_VERSION 19:
// - Added HideKeyboard method
public static final int FORM_COMPONENT_VERSION = 19;
// For FORM_COMPONENT_VERSION 20:
// - The Screen.ShowListsAsJson property was added
public static final int FORM_COMPONENT_VERSION = 20;
// For FUSIONTABLESCONTROL_COMPONENT_VERSION 2:
// - The Fusiontables API was migrated from SQL to V1
......
......@@ -4,9 +4,6 @@
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
// ***********************************************
// If we're not going to go this route with onDestroy, then at least get rid of the DEBUG flag.
package com.google.appinventor.components.runtime;
import java.io.IOException;
......@@ -90,6 +87,7 @@ import com.google.appinventor.components.runtime.util.ViewUtil;
* places and make the appropriate code changes.
*
*/
@DesignerComponent(version = YaVersion.FORM_COMPONENT_VERSION,
category = ComponentCategory.LAYOUT,
description = "Top-level component containing all other components in the program",
......@@ -165,6 +163,8 @@ public class Form extends Activity
private ScaledFrameLayout scaleLayout;
private static boolean sCompatibilityMode;
private static boolean showListsAsJson = false;
// Application lifecycle related fields
private final HashMap<Integer, ActivityResultListener> activityResultMap = Maps.newHashMap();
private final Set<OnStopListener> onStopListeners = Sets.newHashSet();
......@@ -330,8 +330,8 @@ public class Form extends Activity
}
private void defaultPropertyValues() {
Scrollable(false); // frameLayout is created in Scrollable()
Sizing("Fixed");
Scrollable(false); // frameLayout is created in Scrollable()
Sizing("Fixed"); // Note: Only the Screen1 value is used as this is per-project
BackgroundImage("");
AboutScreen("");
BackgroundImage("");
......@@ -341,6 +341,7 @@ public class Form extends Activity
Title("");
ShowStatusBar(true);
TitleVisible(true);
ShowListsAsJson(false); // Note: Only the Screen1 value is used as this is per-project
}
@Override
......@@ -1383,11 +1384,11 @@ public class Form extends Activity
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_SIZING,
defaultValue = "Fixed")
@SimpleProperty(userVisible = false,
// This desc won't apprear as a tooltip, since there's no block, but we'll keep it with the source.
description = "If set to fixed, screen layouts will be created for a single fixed-size screen and autoscaled. " +
"If set to responsive, screen layouts will use the actual resolution of the device. " +
"See the documentation on responsive design in App Inventor for more information. " +
"This property appears on Screen1 only and controls the sizing for all screens in the app.")
// This desc won't apprear as a tooltip, since there's no block, but we'll keep it with the source.
description = "If set to fixed, screen layouts will be created for a single fixed-size screen and autoscaled. " +
"If set to responsive, screen layouts will use the actual resolution of the device. " +
"See the documentation on responsive design in App Inventor for more information. " +
"This property appears on Screen1 only and controls the sizing for all screens in the app.")
public void Sizing(String value) {
// This is used by the project and build server.
// We also use it to adjust sizes
......@@ -1416,16 +1417,49 @@ public class Form extends Activity
// }
// }
/**
* ShowListsAsJson Property Setter
* This only appears in the designer for screen 1
* @param
*/
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN,
defaultValue = "False")
@SimpleProperty(category = PropertyCategory.APPEARANCE, userVisible = false,
// This description won't appear as a tooltip, since there's no block, but we'll keep it with the source.
description = "If false, lists will be converted to strings using Lisp "
+ "notation, i.e., as symbols separated by spaces, e.g., (a 1 b2 (c "
+ "d). If true, lists will appear as in Json or Python, e.g. [\"a\", 1, "
+ "\"b\", 2, [\"c\", \"d\"]]. This property appears only in Screen 1, "
+ "and the value for Screen 1 determines the behavior for all "
+ "screens. The property defaults to \"false\" meaning that the App "
+ "Inventor programmer must explicitly set it to \"true\" if JSON/Python "
+ "syntax is desired. At some point in the future we will alter the "
+ "system so that new projects are created with this property set to "
+ "\"true\" by default. Existing projects will not be impacted. The App "
+ "Inventor programmer can also set it back to \"false\" in newer "
+ "projects if desired. "
)
public void ShowListsAsJson(boolean asJson) {
showListsAsJson = asJson;
}
@SimpleProperty(category = PropertyCategory.APPEARANCE, userVisible = false)
public boolean ShowListsAsJson() {
return showListsAsJson;
}
/**
* Specifies the App Name.
*
* @param aName the display name of the installed application in the phone
*/
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_STRING,
defaultValue = "")
defaultValue = "")
@SimpleProperty(userVisible = false,
description = "This is the display name of the installed application in the phone." +
"If the AppName is blank, it will be set to the name of the project when the project is built.")
description = "This is the display name of the installed application in the phone." +
"If the AppName is blank, it will be set to the name of the project when the project is built.")
public void AppName(String aName) {
// We don't actually need to do anything.
}
......@@ -1649,6 +1683,7 @@ public class Form extends Activity
}
}
/**
* Returns the value that was passed to this screen when it was opened
*
......
......@@ -966,6 +966,20 @@ none
<dd>The requested screen orientation, specified as a text value. Commonly used values are landscape, portrait, sensor, user and unspecified. See the Android developer documentation for ActivityInfo.Screen_Orientation for the complete list of possible settings.</dd>
<dt><code>Scrollable</code></dt>
<dd>When checked, there will be a vertical scrollbar on the screen, and the height of the application can exceed the physical height of the device. When unchecked, the application height is constrained to the height of the device.</dd>
<dt><code>ShowListsAsJson</code> (designer only)</dt>
<dd>
If false, lists will be converted to strings using Lisp notation,
i.e., as symbols separated by spaces, e.g., (a 1 b2 (c d). If true,
lists will appear as in Json or Python, e.g. ["a", 1, "b", 2, ["c",
"d"]]. This property appears only in Screen 1, and the value for
Screen 1 determines the behavior for all screens. The property
defaults to "false" meaning that the App Inventor programmer must
explicitly set it to “true” if JSON/Python syntax is desired. At some
point in the future we will alter the system so that new projects are
created with this property set to "true" by default. Existing projects
will not be impacted. The App Inventor programmer can also set it back
to "false" in newer projects if desired.
</dd>
<dt><code><em>ShowStatusBar</em></code></dt>
<dd>The status bar is the topmost bar on the screen. This property reports whether the status bar is visible.</dd>
<dt><code>Sizing</code> (designer only)</dt>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment