Commits

Romain Vernoux committed 85f974b

UI Improvements + handling toplevel starting failures

  • Participants
  • Parent commits fcdf219

Comments (0)

Files changed (10)

File AndroidManifest.xml

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="jp.co.itpl.ocamlandroid"
       android:versionCode="1"
-      android:versionName="1.0">
+      android:versionName="0.9 beta">
     <application android:icon="@drawable/icon" 
     			 android:label="@string/app_name">
         <activity android:name=".MainActivity"

File res/drawable/ic_menu_add.png

Added
New image

File res/drawable/ic_menu_clear_playlist.png

Added
New image

File res/drawable/ic_menu_close_clear_cancel.png

Added
New image

File res/drawable/ic_menu_set_as.png

Added
New image

File res/layout/editpanel.xml

    	android:orientation="horizontal"
    	android:layout_width="fill_parent"
    	android:layout_height="wrap_content"
-   	android:gravity="right" >
+   	android:gravity="center" >
    	<Button
-	    android:id="@+id/clear_button"
+	    android:id="@+id/add_button_up"
 	    android:layout_width="wrap_content"
-	    android:layout_height="wrap_content" 
-	    android:text="Clear"/>
+	    android:layout_height="wrap_content"
+	    android:text="@string/add_button_up" />
+   	<Button
+	    android:id="@+id/add_button_down"
+	    android:layout_width="wrap_content"
+	    android:layout_height="wrap_content"
+	    android:text="@string/add_button_down" />
+   	<Button
+	    android:id="@+id/delete_button"
+	    android:layout_width="wrap_content"
+	    android:layout_height="wrap_content"
+	    android:text="@string/del_button"/>
    	<Button
 	    android:id="@+id/compile_button"
 	    android:layout_width="wrap_content"
 	    android:layout_height="wrap_content" 
-	    android:text="Compile"/>
+	    android:text="@string/compile_button"/>
   </LinearLayout>
   </LinearLayout>
 </LinearLayout>

File res/values/strings.xml

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <string name="app_name">OCaml Toplevel for Android</string>
-    <string name='addpanel'>Add Panel</string>
-    <string name='clear'>Clear Output</string>
-    <string name="about">About</string>
-    <string name="clear_toast">Output cleared by user</string>
+    <string name='menu_addpanel'>Add Panel</string>
+    <string name='menu_clipboard'>Copy to Clipboard</string>
+    <string name='menu_clear'>Clear Output</string>
+    <string name="menu_about">About</string>
+    <string name="menu_quit">Exit</string>
+    <string name="add_button_up">Panel &#8593;</string>
+    <string name="add_button_down">Panel &#8595;</string>
+    <string name="del_button">Delete</string>
+    <string name="compile_button">Compile</string>
+    <string name="clear_toast">View cleared by user</string>
+    <string name="clipboard_toast">Panel contents merged and copied to Clipboard</string>
     <string name='copyright'>Copyright &#169; 2011 Keigo IMAI\n
 Copyright &#169; 2011 Romain VERNOUX\n
 Copyright &#169; 1995-2011 INRIA\n\n

File src/jp/co/itpl/ocamlandroid/IS01FullScreen.java

-package jp.co.itpl.ocamlandroid;
-
-import java.lang.reflect.Method;
-
-import android.util.Log;
-
-// make full-screen for IS01 phone
-// from http://blog.kcrt.net/2010/08/17/014820
-public class IS01FullScreen {
-	private static final Method setFullScreenMode;
-
-	static {
-		Method meth = null;
-		try {
-			Class<?> sgManager = Class
-					.forName("jp.co.sharp.android.softguide.SoftGuideManager");
-			Class<?> paramstype[] = { boolean.class };
-			meth = sgManager.getMethod("setFullScreenMode", paramstype);
-		} catch (Exception o) {
-			Log.d("is01fullscreen", "failed" + o.getMessage() + ":"
-					+ o.getClass().toString());
-		}
-		setFullScreenMode = meth;
-	}
-
-	public static void invoke() {
-		try {
-			if (setFullScreenMode != null) {
-				setFullScreenMode.invoke(null, true);
-			}
-		} catch (Exception o) {
-			Log.d("is01fullscreen", "failed");
-		}
-	}
-
-}

File src/jp/co/itpl/ocamlandroid/MainActivity.java

  - EditPanel system
  - Orientation change bug fixed
  - Logo
+ 
+ 08/03/11
+ - Menu Icons
+ - Copy to clipboard function
+ - The application now handles toplevel starting errors.
+ - Beta release \o/
+ 
 */
 
 /*   TO DO
  
- - Clean the mess
- - Menu icons
- - Copy to clipboard function
+ - 
+ - Wait for Feedbacks
 
 */
 
  	Sometimes, a new update arrives before the previous scroll has finished
  	Then, we have to queue the scroll process with a runnable, or else the screen won't scroll
  	and the last lines will appear under the bottom of the screen.
- 
- Compile button 
- 	-> Is the toplevel "compiling" or "executing" ? I'm not sure.
+
  
  */
 
 import android.content.Intent;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.text.ClipboardManager;
 import android.text.Html;
 import android.util.Log;
 import android.view.LayoutInflater;
 
 public class MainActivity extends Activity {
 	public static final int MENU_ADDPANEL = 0;
-	public static final int MENU_CLEAR = 1;
-	public static final int MENU_ABOUT = 2;
+	public static final int MENU_CLIPBOARD = 1;
+	public static final int MENU_CLEAR = 2;
+	public static final int MENU_ABOUT = 3;
+	public static final int MENU_QUIT = 4;
 	public static final int FROM_TOPLEVEL = 1;
 	public static final int FROM_USER = 2;
+	public static final int EDITTEXT = 0;
+	public static final int NUMBER_OF_BUTTONS = 4;
+	public static final int COMPILE_BUTTON = 1;
+	public static final int DELETE_BUTTON = 2;
+	public static final int PANEL_UP = 3;
+	public static final int PANEL_DOWN = 4;
 	public static final String TOPLEVEL_START_TAG = "";
 	public static final String TOPLEVEL_END_TAG = "";
 	public static final String USER_START_TAG = "<b>";
 		
 		Object[] tab = (Object[]) getLastNonConfigurationInstance();
 		if (tab == null){ // The application has just been launched by the user
-			addEditPanel();
+			tabHost.setCurrentTab(1);
+			addEditPanel(0);
 		}
 		else { // The application just resumed from an orientation change
 			for (int k = 1; k < tab.length-1; k++){
-				addEditPanel();
+				addEditPanel(k-1);
 				((EditText) findViewById(10*k)).setText((String)tab[k]);
 			}
 			tabHost.setCurrentTab((Integer) tab[tab.length-1]);
 					
 	}
 	
-	
-	
+	/*
 	@Override
 	public void onResume() { 	
 		super.onResume();
 		IS01FullScreen.invoke();
 	}
+	*/
 
 	@Override
 	public Object onRetainNonConfigurationInstance() {
 		return tab;
 	}
 	
-	public void addEditPanel() {
+	public void addEditPanel(final int index) {
 		LayoutInflater vi = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 		LinearLayout layout = (LinearLayout) vi.inflate(R.layout.editpanel, null);
 		
-		
 		EditText edit = (EditText) layout.findViewById(R.id.input);
 		Button compile_button = (Button) layout.findViewById(R.id.compile_button);
-		Button clear_button = (Button) layout.findViewById(R.id.clear_button);
-		edit.setId(10*editPanel_number+0);
-		compile_button.setId(10*editPanel_number+1);
-		clear_button.setId(10*editPanel_number+2);
+		Button delete_button = (Button) layout.findViewById(R.id.delete_button);
+		Button panel_up_button = (Button) layout.findViewById(R.id.add_button_up);
+		Button panel_down_button = (Button) layout.findViewById(R.id.add_button_down);
+		
+		//Updates the IDs
+		for(int k = index+1; k < editPanel_number; k++) {
+			for (int j = 0; j <= NUMBER_OF_BUTTONS; j++){
+				findViewById(10*k + j).setId(10*(k+1)+j);
+			} 
+		}
+		
+		edit.setId(10*(index+1)+EDITTEXT);
+		compile_button.setId(10*(index+1)+COMPILE_BUTTON);
+		delete_button.setId(10*(index+1)+DELETE_BUTTON);
+		panel_up_button.setId(10*(index+1)+PANEL_UP);
+		panel_down_button.setId(10*(index+1)+PANEL_DOWN);
 		// For instance, the compile_button in the third editPanel has ID = 3*10+1 = 21 where 3 stands for "third panel" and "1" for "compile_button".
 		
 		
 				@Override
 				public void onClick(View arg0) {
 					// TODO Auto-generated method stub
-					if(out!=null && !"".equals(((EditText) findViewById(arg0.getId()-1)).getText().toString().trim())) {
+					if(out!=null && !"".equals(((EditText) findViewById((arg0.getId()/10)*10 + EDITTEXT)).getText().toString().trim())) {
 						
 						// Hide the soft Keyboard manually
 						InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-						mgr.hideSoftInputFromWindow(((EditText) findViewById(arg0.getId()-1)).getWindowToken(), 0);
+						mgr.hideSoftInputFromWindow(((EditText) findViewById((arg0.getId()/10)*10 + EDITTEXT)).getWindowToken(), 0);
 						//
 						
 						tabHost.setCurrentTab(1);
-						String line = ((EditText) findViewById(arg0.getId()-1)).getText().toString()+"\n";
+						String line = ((EditText) findViewById((arg0.getId()/10)*10 + EDITTEXT)).getText().toString()+"\n";
 						println(line, FROM_USER);
 						out.println(line);
 						out.flush();
 				
 			}
 		);
-		clear_button.setOnClickListener(
+		
+		delete_button.setOnClickListener(
 				new OnClickListener() {
 
 					@Override
 					public void onClick(View arg0) {
 						// TODO Auto-generated method stub
-						((EditText) findViewById(arg0.getId()-2)).setText("");
+						delEditPanel(arg0.getId()/10);
+					}
+					
+				}
+		);
+		
+		panel_up_button.setOnClickListener(
+				new OnClickListener() {
+
+					@Override
+					public void onClick(View arg0) {
+						// TODO Auto-generated method stub
+						addEditPanel(arg0.getId()/10-1);
+					}
+					
+				}
+		);
+		
+		panel_down_button.setOnClickListener(
+				new OnClickListener() {
+
+					@Override
+					public void onClick(View arg0) {
+						// TODO Auto-generated method stub
+						addEditPanel(arg0.getId()/10);
 					}
 					
 				}
 		);
 		
 		tabHost.setCurrentTab(0);
-		editPanelView.addView(layout);
+		editPanelView.addView(layout,index);
 		scrollView_editor.post(new Runnable() { 
 		    public void run() { 
-		        scrollView_editor.smoothScrollTo(0, editPanelView.getHeight()); 
+		        scrollView_editor.smoothScrollTo(0,((View) findViewById(10*(index+1)+COMPILE_BUTTON)).getBottom()); 
 		    } 
 		}); 
 		
 		editPanel_number ++;
 	}
 	
-
+	public void delEditPanel(int index) {
+		// Removes the View
+		editPanelView.removeView((View) findViewById(10*index+EDITTEXT).getParent().getParent());
+		// Updates the IDs
+		for(int k = index+1; k < editPanel_number; k++) {
+			for (int j = 0; j <= NUMBER_OF_BUTTONS; j++){
+				findViewById(10*k + j).setId(10*(k-1)+j);
+			} 
+		}
+		editPanel_number--;
+	}
+	
 	public void println(String line, int origin) { 
-		Log.d(TAG, "console output:"+line);
+		Log.d(TAG, "console output: "+line);
 		if(origin == FROM_USER){
 			output_text = output_text.concat(USER_START_TAG).concat(line).concat(USER_END_TAG).replace("\n", "<br />");
 		}
 		Log.d(TAG, "console clear");
 		output_text = "";
 		println("# ", FROM_TOPLEVEL);
+		tabHost.setCurrentTab(1);
 		Toast.makeText(MainActivity.this, R.string.clear_toast, Toast.LENGTH_SHORT).show();
 	}
 	
 	public boolean onCreateOptionsMenu(Menu menu) { 
 		super.onCreateOptionsMenu(menu);
 		
-		menu.add(Menu.NONE, MENU_ADDPANEL, Menu.NONE, R.string.addpanel);
-		menu.add(Menu.NONE, MENU_CLEAR, Menu.NONE, R.string.clear);
-		menu.add(Menu.NONE, MENU_ABOUT, Menu.NONE, R.string.about)
-		    .setIcon(android.R.drawable.ic_menu_info_details);
+		menu.add(Menu.NONE, MENU_ADDPANEL, Menu.NONE, R.string.menu_addpanel)
+			.setIcon(R.drawable.ic_menu_add);
+		menu.add(Menu.NONE, MENU_CLIPBOARD, Menu.NONE, R.string.menu_clipboard)
+		.setIcon(R.drawable.ic_menu_set_as);
+		menu.add(Menu.NONE, MENU_CLEAR, Menu.NONE, R.string.menu_clear)
+			.setIcon(R.drawable.ic_menu_clear_playlist);
+		menu.add(Menu.NONE, MENU_ABOUT, Menu.NONE, R.string.menu_about)
+		    .setIcon(R.drawable.ic_menu_info_details);
+		menu.add(Menu.NONE, MENU_QUIT, Menu.NONE, R.string.menu_quit)
+	    	.setIcon(R.drawable.ic_menu_close_clear_cancel);
 		
 		return true;
 	}
 	public boolean onOptionsItemSelected(MenuItem item) { 
 		switch (item.getItemId()) {
 		case MENU_ADDPANEL:
-			addEditPanel();
+			addEditPanel(editPanel_number-1);
+			return true;
+		case MENU_CLIPBOARD:
+			String content = "";
+			for(int k = 1; k < editPanel_number; k++){
+				content = content.concat(((EditText) findViewById(10*k+ EDITTEXT)).getText().toString()).concat("\n\n");
+			}
+			content = content.substring(0, content.length()-2);
+			ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); 
+			clipboard.setText(content);
+			tabHost.setCurrentTab(0);
+			Toast.makeText(MainActivity.this, R.string.clipboard_toast, Toast.LENGTH_SHORT).show();
 			return true;
 		case MENU_CLEAR:
 			clear();
 			Intent intent_about = new Intent(MainActivity.this, About.class);
 			startActivity(intent_about);
 			return true;
+		case MENU_QUIT:
+			android.os.Process.killProcess(android.os.Process.myPid());
+			return true;
 		default:
 			return super.onOptionsItemSelected(item);
 		}
 			try {
 				Object[] tab = (Object[]) getLastNonConfigurationInstance();
 				if(tab == null) {
-					toplevel = new OcamlTop(MainActivity.this);
+					try {
+						toplevel = new OcamlTop(MainActivity.this);
+					} catch (Exception e) {
+						// TODO Auto-generated catch block
+						output_text="";
+						println("/!\\ Fatal Error : unable to start the Toplevel /!\\\nPlease contact us to report this bug !",FROM_TOPLEVEL);
+					}
 					Log.d(TAG,"New Toplevel created");
 				}
 				else {
 										 
 				}
 			} catch (IOException e) {
-				Log.e(TAG, "reading stdout/stderr error", e); //FIXME
+				Log.e(TAG, "Datas has been lost", e); 
+				Toast.makeText(MainActivity.this, "Datas has been lost. Please compile again.", Toast.LENGTH_SHORT).show();
 			}
 			
 			return null;  

File src/jp/co/itpl/ocamlandroid/OcamlTop.java

 	public static final String ASSETS_STDLIBPATH = "ocaml-stdlib";
 	public static final String STDSTREAM_NAME = "jp.co.itpl.ocamltop";
 
-	private void prepareStdlib(Context context) {
+	private void prepareStdlib(Context context) throws Exception {
 		File cache = context.getCacheDir();
 		AssetManager assets = context.getAssets();
 		try {
 			String[] files = assets.list(ASSETS_STDLIBPATH);
-			Log.d(TAG, "copying " + files.length + " files of stdlib..");
+			Log.d(TAG, "copying " + files.length + " files of stdlib...");
 			for (String file : files) {
 				InputStream in = null;
 				OutputStream out = null;
 				try {
 					in = assets.open(ASSETS_STDLIBPATH + File.separator + file);
-					String outfile = cache.getAbsolutePath() + File.separator
-							+ file;
+					String outfile = cache.getAbsolutePath() + File.separator + file;
 					out = new FileOutputStream(outfile);
 					IOUtils.copy(in, out);
 				} finally {
 			Log.d(TAG, "copy complete.");
 		} catch (IOException e) {
 			Log.e(TAG, "stdlib copy error", e);
-			// FIXME: exit
+			throw(new Exception("Stdlib copy error. The program will be killed."));
 		}
 	}
 
 	public final LocalSocket stream;
 
-	public OcamlTop(final Context context) throws IOException {
-		prepareStdlib(context);
+	public OcamlTop(final Context context) throws Exception {
+		try {
+			prepareStdlib(context);
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			throw(e);
+		}
 		Native.chdir(context.getCacheDir().getAbsolutePath());
 
 		Log.i(TAG, "connecting std stream");