Commits

Romain Vernoux committed 376f60d Draft

New version!

Comments (0)

Files changed (7)

res/layout/editpanel.xml

-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
-  xmlns:android="http://schemas.android.com/apk/res/android"
-  android:layout_width="fill_parent"
-  android:layout_height="wrap_content">
-  <LinearLayout
-  	android:layout_width="fill_parent" 
-    android:layout_height="wrap_content" 
-    android:orientation="vertical"
-    android:layout_marginBottom="20dip"
-    android:layout_marginLeft="5dip"
-    android:layout_marginRight="5dip">
-  <TextView
-  	android:layout_width="wrap_content"
-  	android:layout_height="wrap_content"
-  	android:text="OCaml User Input:" />
-  <EditText
-    android:id="@+id/input"
-    android:layout_width="fill_parent" 
-    android:layout_height="wrap_content" />
-  <LinearLayout
-   	android:orientation="horizontal"
-   	android:layout_width="fill_parent"
-   	android:layout_height="wrap_content"
-   	android:gravity="center" >
-   	<Button
-	    android:id="@+id/add_button_up"
-	    android:layout_width="fill_parent"
-	    android:layout_height="wrap_content"
-	    android:layout_weight="1"
-	    android:text="@string/add_button_up" />
-   	<Button
-	    android:id="@+id/add_button_down"
-	    android:layout_width="fill_parent"
-	    android:layout_height="wrap_content"
-	    android:layout_weight="1"
-	    android:text="@string/add_button_down" />
-   	<Button
-	    android:id="@+id/delete_button"
-	    android:layout_width="fill_parent"
-	    android:layout_height="wrap_content"
-	    android:layout_weight="1"
-	    android:text="@string/del_button"/>
-   	<Button
-	    android:id="@+id/compile_button"
-	    android:layout_width="fill_parent"
-	    android:layout_height="wrap_content"
-	    android:layout_weight="1" 
-	    android:text="@string/compile_button"/>
-  </LinearLayout>
-  </LinearLayout>
-</LinearLayout>

res/layout/main.xml

 <TabHost xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/tabhost"
     android:layout_width="fill_parent"
-    android:layout_height="fill_parent">
-	<LinearLayout 
-	    android:orientation="vertical"
-	    android:layout_width="fill_parent"
-	    android:layout_height="fill_parent"
-	    android:gravity="fill_vertical">
-		<TabWidget
+    android:layout_height="fill_parent" >
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:gravity="fill_vertical"
+        android:orientation="vertical" >
+
+        <TabWidget
             android:id="@android:id/tabs"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content" />
+
         <FrameLayout
             android:id="@android:id/tabcontent"
             android:layout_width="fill_parent"
             android:layout_height="fill_parent"
-            android:padding="5dip">
-            
-            
-            		<!-- Tab 1 start -->
-            		<ScrollView
-					    	android:id="@+id/tab1"
-					    	android:layout_width="fill_parent" 
-						    android:layout_height="wrap_content" >	
-		            <LinearLayout 
-		            	android:id="@+id/editPanelView"
-					    android:orientation="vertical"
-					    android:layout_width="fill_parent"
-					    android:layout_height="fill_parent">
-					    
-					</LinearLayout>    
-					    
-					</ScrollView>    
-					    <!--  
-			            
-					    -->
-		         
-		            <!-- Tab 1 end -->
-		            
-		            
-		            <!-- Tab 2 start -->
-		            <LinearLayout 
-		            	android:id="@+id/tab2"
-					    android:orientation="vertical"
-					    android:layout_width="fill_parent"
-					    android:layout_height="fill_parent">
-			            <ScrollView
-							android:id="@+id/scrollview_toplevel"
-							android:layout_width="fill_parent"
-						    android:layout_height="fill_parent"
-							android:layout_marginTop="10dip"
-						    android:layout_marginLeft="10dip"
-						    android:layout_marginRight="10dip"
-						    android:layout_marginBottom="10dip">
-						    
-							<TextView  
-							    android:id="@+id/output"
-							    android:layout_width="fill_parent" 
-							    android:layout_height="wrap_content"
-							    android:layout_marginBottom="10dip"
-							    android:lineSpacingMultiplier="1.2"
-							    />
-						</ScrollView>
-					</LinearLayout>
-					<!-- Tab 2 end -->
-					
-					
-		</FrameLayout>		
-	</LinearLayout>
-</TabHost>
+            android:padding="5dip" >
 
+            <!-- Tab 1 start -->
+
+            <LinearLayout
+                android:id="@+id/tab1"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:layout_marginBottom="20dip"
+                android:layout_marginLeft="5dip"
+                android:layout_marginRight="5dip"
+                android:orientation="vertical" >
+                
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/editor_hint" />
+
+                <EditText
+                    android:id="@+id/editor"
+                    android:layout_width="fill_parent"
+                    android:layout_height="0dp"
+                    android:layout_weight="1"
+                    android:inputType="textMultiLine" />
+
+                <LinearLayout
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="center"
+                    android:orientation="horizontal" >
+
+                    <Button
+                        android:id="@+id/compile_paragraph"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="@string/compile_paragraph" />
+
+                    <Button
+                        android:id="@+id/compile_all"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="@string/compile_all" />
+                </LinearLayout>
+            </LinearLayout>
+
+
+            <!-- Tab 1 end -->
+
+
+            <!-- Tab 2 start -->
+
+            <ListView
+                android:id="@+id/console_output"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:dividerHeight="0px"
+                android:transcriptMode="alwaysScroll" />
+            <!-- android:stackFromBottom="true" -->
+
+
+            <!-- Tab 2 end -->
+
+        </FrameLayout>
+    </LinearLayout>
+
+</TabHost>

res/layout/output_sublayout.xml

+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/text"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginLeft="5dp"
+    android:layout_marginRight="5dp" />

res/values/strings.xml

     <string name='menu_save'>Save Sources</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="menu_quit">Exit</string>    
+    <string name="editor_hint">OCaml user input:</string>
+    <string name="compile_paragraph">Compile paragraph</string>
+    <string name="compile_all">Compile all</string>
     <string name="clear_toast">View cleared by user</string>
     <string name="clipboard_toast">Sources merged and copied to Clipboard</string>
     <string name="file_external_toast">Sources merged and saved in sdcard/ocaml/.</string>
     <string name="file_directory_not_found">Directory not found or empty.</string>
     <string name="data_lost">Data has been lost. Please compile again.</string>
     <string name="toplevel_start_fail">/!\\ Fatal Error : unable to start the Toplevel /!\\\nPlease restart the application.</string>   
-    <string name='copyright'>Copyright &#169; 2011 Keigo IMAI\n
-Copyright &#169; 2011 Romain VERNOUX\n
-Copyright &#169; 1995-2011 INRIA\n\n
+    <string name='copyright'>Copyright &#169; 2012 Keigo IMAI\n
+Copyright &#169; 2012 Romain VERNOUX\n
+Copyright &#169; 1995-2012 INRIA\n\n
 
 This program includes compiled code of Objective Caml 3.12.\n\n
 

src/fr/vernoux/ocaml/MainActivity.java

  - Saving/opening files with preserved panels
  - Output display performance improvements
  
-*/
+ */
 
 /*   TO DO
  TODO requestRectangle on listview?
-*/
-
+ */
 
 /* NOTES & COMMENTS
- 
+
  Why Asynctask ?
- 	-> They are running in a separate thread and permit to access datas from the UI Thread.
- 	-> We can thus easily modify (TextView outView) from another thread : cool!
- 	-> Didn't have time to try, but it is apparently easy to keep such threads alive during change orientation.
- 	
+ -> They are running in a separate thread and permit to access datas from the UI Thread.
+ -> We can thus easily modify (TextView outView) from another thread : cool!
+ -> Didn't have time to try, but it is apparently easy to keep such threads alive during change orientation.
+
  Why a Runnable to scroll ?
- 	-> Our backthread is sending updates very fast to the UI Thread.
- 	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.
+ -> Our backthread is sending updates very fast to the UI Thread.
+ 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.
 
- 
+
  */
 
-
 package fr.vernoux.ocaml;
 
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.util.regex.Pattern;
-
-
-
+import java.util.ArrayList;
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Environment;
-import android.os.Handler;
-import android.text.Html;
 import android.util.Log;
-import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
+import android.widget.ListView;
 import android.widget.TabHost;
 import android.widget.TabHost.TabSpec;
 import android.widget.TextView;
 import android.widget.Toast;
 
 public class MainActivity extends Activity {
-	public static final int MENU_ADDPANEL = 0;
-	public static final int MENU_SAVE = 1;
-	public static final int MENU_OPEN = 2;
-	public static final int MENU_CLEAR = 3;
-	public static final int MENU_ABOUT = 4;
-	public static final int MENU_QUIT = 5;
+	
+	
+	private static final int MENU_SAVE = 1;
+	private static final int MENU_OPEN = 2;
+	private static final int MENU_CLEAR = 3;
+	private static final int MENU_ABOUT = 4;
+	private static final int MENU_QUIT = 5;
 	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 int FILE_NAME = 0;
-	public static final int OVERWRITE = 1;
-	public static final int OPEN_FILE = 2;
-	public static final String TOPLEVEL_START_TAG = "";
-	public static final String TOPLEVEL_END_TAG = "";
-	public static final String USER_START_TAG = "<b>";
-	public static final String USER_END_TAG = "</b>";
-	public static final String TAG = "ocaml-android";
-	public static final String PANEL_TAG = "(* OCAML-ANDROID-PANEL *)";
-	public static final long REFRESH_INTERVAL = 100;
-	
+	private static final int FILE_NAME = 0;
+	private static final int OVERWRITE = 1;
+	private static final int OPEN_FILE = 2;
+	private static final int BACKTHREAD_IND = 0;
+	private static final int EDITOR_IND = 1;
+	private static final int TAB_IND = 2;
+	private static final int OUTPUT_IND = 3;
+	private static final int ADAPTER_IND = 4;
+
+	private static final String TAG = "ocaml-android";
+
 	private TabHost tabHost;
-	private TextView outView; 
-	private static StringBuilder output_text; //Static is to avoid painful java stuff on orientation changes
-	private static ScrollView scrollView_toplevel;
-	private ScrollView scrollView_editor;
+	private ListView outView;
+	private OutputAdapter outAdapter;
+	private ArrayList<OutputLine> output_text; // Static is to avoid
+														// painful java stuff on
+														// orientation changes
+	private StringBuffer output_buffer;
 	private PrintWriter out = null;
-	private InputStream in = null;
-	private OcamlTop toplevel = null;
 	private BackThread backThread = null;
-	private LinearLayout editPanelView = null;
-	private int editPanel_number;
+	private TextView editor;
 	private String fileName = "";
-	private Handler outputUpdater = new Handler();
+	// private Handler outputUpdater = new Handler();
 	private static final Object lock = new Object();
-	private static boolean output_upToDate = true;
-	
-	
+
+	// private static boolean output_upToDate = true;
+
+	@SuppressWarnings("unchecked")
 	@Override
- 	public void onCreate(Bundle savedInstanceState) {
+	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		setContentView(R.layout.main);
-		
-		tabHost=(TabHost)findViewById(R.id.tabhost);
+
+		tabHost = (TabHost) findViewById(R.id.tabhost);
 		tabHost.setup();
-		TabSpec spec1=tabHost.newTabSpec("Tab 1");
-		spec1.setIndicator("Code Editor",getResources().getDrawable(R.drawable.ide_tab));
+		TabSpec spec1 = tabHost.newTabSpec("Tab 1");
+		spec1.setIndicator("Code Editor",
+				getResources().getDrawable(R.drawable.ide_tab));
 		spec1.setContent(R.id.tab1);
-		TabSpec spec2=tabHost.newTabSpec("Tab 2");
-		spec2.setIndicator("OCaml Toplevel",getResources().getDrawable(R.drawable.toplevel_tab));
-		spec2.setContent(R.id.tab2);
+		TabSpec spec2 = tabHost.newTabSpec("Tab 2");
+		spec2.setIndicator("OCaml Toplevel",
+				getResources().getDrawable(R.drawable.toplevel_tab));
+		spec2.setContent(R.id.console_output);
 		tabHost.addTab(spec1);
 		tabHost.addTab(spec2);
 		tabHost.setCurrentTab(1);
-		
-		outView = (TextView) findViewById(R.id.output);
-		scrollView_toplevel = (ScrollView) findViewById(R.id.scrollview_toplevel);
-		scrollView_editor = (ScrollView) findViewById(R.id.tab1);
-		editPanelView = (LinearLayout) findViewById(R.id.editPanelView);
-		editPanel_number = 1;
-		
-		
-		
-		
+
+		output_buffer = new StringBuffer();
+
+		outView = (ListView) findViewById(R.id.console_output);
+
+		editor = (TextView) findViewById(R.id.editor);
+		Button compile_all = (Button) findViewById(R.id.compile_all);
+		compile_all.setOnClickListener(new OnClickListener() {
+
+			public void onClick(View arg0) {
+
+				if (out != null
+						&& !"".equals(editor.getText().toString().trim())) {
+
+					// Hide the soft Keyboard manually
+					InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+					mgr.hideSoftInputFromWindow(editor.getWindowToken(), 0);
+
+					tabHost.setCurrentTab(1);
+					String line = editor.getText().toString() + "\n";
+					parseAndPrint(line, FROM_USER);
+
+					out.println(line);
+					out.flush();
+				}
+			}
+
+		});
+
 		Object[] tab = (Object[]) getLastNonConfigurationInstance();
-		if (tab == null){ // The application has just been launched by the user
-			output_text = new StringBuilder("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
-			FileInputStream fis = null;;
-			InputStreamReader isr = null;;
+		if (tab == null) { // The application has just been launched by the user
+
+			output_text = new ArrayList<OutputLine>();
+			outAdapter = new OutputAdapter(this, output_text);
+			outView.setAdapter(outAdapter);
+
+			FileInputStream fis = null;
+			;
+			InputStreamReader isr = null;
+			;
 			BufferedReader br = null;
 			StringBuilder content = new StringBuilder();
-			addEditPanel(0);
 			try {
 				fis = openFileInput("autosave");
 				isr = new InputStreamReader(fis);
-		        br = new BufferedReader(isr);
-		        String line;
-		        while ((line = br.readLine()) != null) {
-		             content.append(line).append("\n");
-		        }
-		        if(content.length() != 0){
-					String[] parsed_source = parse(content.substring(0, content.length()-1));
-			        for(String panel: parsed_source){
-			        	if (!(panel = panel.trim()).equals("")){
-			        		int current = editPanel_number-1;
-			        		addEditPanel(current-1);
-			        		((EditText) findViewById(10*current + EDITTEXT)).setText(panel);	
-			        	}
-			        }
+				br = new BufferedReader(isr);
+				String line;
+				while ((line = br.readLine()) != null) {
+					content.append(line).append("\n");
 				}
+				editor.setText(content);
 			} catch (FileNotFoundException e) {
-				//It's okay, first launch for example. Don't care anyway.
-				addEditPanel(0);
+				// It's okay, first launch for example. Don't care anyway.
 			} catch (IOException e) {
-				addEditPanel(0);
+				// Hmm?
+				e.printStackTrace();
 			}
-			
-			
+
 			tabHost.setCurrentTab(1);
-			
+
+			backThread = new BackThread();
+			backThread.execute();
+		} else { // The application resumed from an orientation change
+			editor.setText((String) tab[EDITOR_IND]);
+			tabHost.setCurrentTab((Integer) tab[TAB_IND]);
+			output_text = (ArrayList<OutputLine>) tab[OUTPUT_IND];
+			backThread = (BackThread) tab[BACKTHREAD_IND];
+			outAdapter = (OutputAdapter) tab[ADAPTER_IND];
+			out = backThread.getOutput();
+			outView.setAdapter(outAdapter);
 		}
-		else { // The application just resumed from an orientation change
-			for (int k = 1; k < tab.length-1; k++){
-				addEditPanel(k-1);
-				((EditText) findViewById(10*k)).setText((String)tab[k]);
-			}
-			tabHost.setCurrentTab((Integer) tab[tab.length-1]);
-		}
-		
-		
-		
-		println("",FROM_USER); // Causes the view to display the old text after a orientation change.
-		
-		/*
-		outputUpdater = new Timer("outputUpdater");
-		outputUpdater.schedule(new OutputUpdaterTask(), 0, 2000);
-		*/
-		
-		outputUpdater.post(outputUpdaterTask);
-		backThread = new BackThread();
-		backThread.execute();	
-		
 	}
-	
-	/*
-	@Override
-	public void onResume() { 	
-		super.onResume();
-		IS01FullScreen.invoke();
-	}
-	*/
-	
-	public void onPause(){
+
+	public void onPause() {
 		super.onPause();
-		outputUpdater.removeCallbacks(outputUpdaterTask);
-		FileOutputStream fos = null;;
+		// outputUpdater.removeCallbacks(outputUpdaterTask);
+		FileOutputStream fos = null;
+		;
 		try {
 			fos = openFileOutput("autosave", Context.MODE_PRIVATE);
-			fos.write(merge().getBytes());
+			fos.write(editor.getText().toString().getBytes());
 			fos.close();
 		} catch (FileNotFoundException e) {
 			e.printStackTrace();
 		} catch (IOException e) {
 			e.printStackTrace();
-		}   
+		}
 	}
-	
-	public void onResume(){
-		super.onResume();
-		outputUpdater.post(outputUpdaterTask);
-	}
+
+	/*
+	 * public void onResume(){ super.onResume();
+	 * outputUpdater.post(outputUpdaterTask); }
+	 */
 
 	@Override
 	public Object onRetainNonConfigurationInstance() {
-		// We will save 3 things for the next instance : the current toplevel, the texts in the editPanels and the current tab.
-		Object[] tab = new Object[editPanel_number+1];
-		tab[0] = toplevel;
-		for(int k = 1; k <= tab.length-2; k++){
-			tab[k] = ((EditText) findViewById(10*k)).getText().toString();
-		}
-		tab[tab.length-1] = tabHost.getCurrentTab();
+		Object[] tab = new Object[5];
+		tab[BACKTHREAD_IND] = backThread;
+		tab[EDITOR_IND] = editor.getText().toString();
+		tab[TAB_IND] = tabHost.getCurrentTab();
+		tab[OUTPUT_IND] = output_text;
+		tab[ADAPTER_IND] = outAdapter;
 		return tab;
 	}
-	
-	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 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);
-			} 
+
+	private void clearOutputBuffer() {
+		if (output_buffer.length() > 0)
+			output_buffer.delete(0, output_buffer.length());
+	}
+
+	private void parseAndPrint(String line, int origin) {
+		synchronized (lock) {
+			clearOutputBuffer();
+			for (int i = 0; i < line.length(); i++) {
+				char c = line.charAt(i);
+				if (c == '\n') {
+					println(output_buffer.toString(), origin, true);
+					clearOutputBuffer();
+				} else {
+					output_buffer.append(c);
+				}
+			}
+			if (output_buffer.length() != 0) {
+				println(output_buffer.toString(), origin, false);
+				clearOutputBuffer();
+			}
 		}
-		
-		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 = 31 where 3 stands for "third panel" and "1" for "compile_button".
-		
-		
-		
-		compile_button.setOnClickListener(
-			new OnClickListener() {
+	}
 
-				public void onClick(View arg0) {
-					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()/10)*10 + EDITTEXT)).getWindowToken(), 0);
-						//
-						
-						tabHost.setCurrentTab(1);
-						String line = ((EditText) findViewById((arg0.getId()/10)*10 + EDITTEXT)).getText().toString()+"\n";
-						println(line, FROM_USER);
-						out.println(line);
-						out.flush();
-					}
-				}
-				
+	private void println(String line, int origin, boolean line_finished) {
+		synchronized (lock) {
+			OutputLine last_line = null;
+			if (!output_text.isEmpty()) {
+				last_line = output_text.get(output_text.size() - 1);
+			} else {
+				last_line = new OutputLine("", origin);
+				output_text.add(last_line);
 			}
-		);
-		
-		delete_button.setOnClickListener(
-				new OnClickListener() {
+			last_line.addText(line, origin);
+			if (line_finished) {
+				output_text.add(new OutputLine("", origin));
+			}
+			outAdapter.notifyDataSetChanged();
+		}
+	}
 
-					public void onClick(View arg0) {
-						if(editPanel_number > 2){
-							delEditPanel(arg0.getId()/10);
-						} else {
-							((EditText) findViewById((arg0.getId()/10)*10+ EDITTEXT)).setText("");
-						}
-					}
-					
-				}
-		);
-		
-		panel_up_button.setOnClickListener(
-				new OnClickListener() {
+	private void clear() {
+		Log.d(TAG, "console clear");
+		output_text.clear();
+		println("# ", FROM_TOPLEVEL, false);
+		tabHost.setCurrentTab(1);
+		Toast.makeText(MainActivity.this, R.string.clear_toast,
+				Toast.LENGTH_SHORT).show();
+	}
 
-					public void onClick(View arg0) {
-						addEditPanel(arg0.getId()/10-1);
-					}
-					
-				}
-		);
-		
-		panel_down_button.setOnClickListener(
-				new OnClickListener() {
-
-					public void onClick(View arg0) {
-						addEditPanel(arg0.getId()/10);
-					}
-					
-				}
-		);
-		
-		tabHost.setCurrentTab(0);
-		editPanelView.addView(layout,index);
-		scrollView_editor.post(new Runnable() { 
-		    public void run() { 
-		    	((View) findViewById(10*(index+1)+EDITTEXT)).requestFocus();
-		    } 
-		}); 
-		
-		edit.requestFocus();
-		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) { 
-		synchronized(lock){
-			String line2 = line.replace("<", "&lt;").replace("\n", "<br />");
-			if(origin == FROM_USER){
-				output_text.append(USER_START_TAG).append(line2).append(USER_END_TAG);
-			}
-			else {
-				output_text.append(TOPLEVEL_START_TAG).append(line2).append(TOPLEVEL_END_TAG);
-			}
-			output_upToDate = false;
-		}		
-	}
-	
-	private void clear() { 
-		Log.d(TAG, "console clear");
-		output_text.delete(0, output_text.length());
-		println("# ", FROM_TOPLEVEL);
-		tabHost.setCurrentTab(1);
-		Toast.makeText(MainActivity.this, R.string.clear_toast, Toast.LENGTH_SHORT).show();
-	}
-	
- 	private String merge(){
-		StringBuilder content = new StringBuilder();
-		for(int k = 1; k < editPanel_number; k++){
-			content.append(PANEL_TAG)
-				.append("\n")
-				.append(((EditText) findViewById(10*k+ EDITTEXT)).getText().toString())
-				.append("\n\n");
-		}
-		return(content.substring(0, content.length()-2));
-	}
-	
-	private String[] parse(String text){
-		return(text.split(Pattern.quote(PANEL_TAG)));
-	}
-	
 	private void saveFile(String name, boolean overwrite) {
 		String state = Environment.getExternalStorageState();
-		FileOutputStream fOut = null; 
-        OutputStreamWriter osw = null;
-	    if (Environment.MEDIA_MOUNTED.equals(state)) {
-	    	String path = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator + "ocaml";
-	    	new File(path).mkdirs();
-	    	File file = new File(path + File.separator + name);
-	    	if(file.isFile() && !overwrite){
-	    		Intent intent = new Intent(MainActivity.this, FileOverwrite.class);
-	    		startActivityForResult(intent, OVERWRITE);
-	    	} else {
-				try{ 
-		           fOut = new FileOutputStream(file);       
-		            osw = new OutputStreamWriter(fOut); 
-		            osw.write(merge()); 
-	                Toast.makeText(MainActivity.this, R.string.file_external_toast, Toast.LENGTH_LONG).show();
-	            } catch (Exception e) {       
-	            	Toast.makeText(MainActivity.this, R.string.file_write_fail, Toast.LENGTH_LONG).show();
-	            } finally {
-	            	try {
+		FileOutputStream fOut = null;
+		OutputStreamWriter osw = null;
+		if (Environment.MEDIA_MOUNTED.equals(state)) {
+			String path = Environment.getExternalStorageDirectory()
+					.getAbsolutePath() + File.separator + "ocaml";
+			new File(path).mkdirs();
+			File file = new File(path + File.separator + name);
+			if (file.isFile() && !overwrite) {
+				Intent intent = new Intent(MainActivity.this,
+						FileOverwrite.class);
+				startActivityForResult(intent, OVERWRITE);
+			} else {
+				try {
+					fOut = new FileOutputStream(file);
+					osw = new OutputStreamWriter(fOut);
+					osw.write(editor.getText().toString());
+					Toast.makeText(MainActivity.this,
+							R.string.file_external_toast, Toast.LENGTH_LONG)
+							.show();
+				} catch (Exception e) {
+					Toast.makeText(MainActivity.this, R.string.file_write_fail,
+							Toast.LENGTH_LONG).show();
+				} finally {
+					try {
 						osw.close();
 					} catch (IOException e) {
 						e.printStackTrace();
-					} 
-	            }
-	            Log.d(TAG,"File saved in " + path + ".");
-	    	}
-	    } else if (Environment.MEDIA_SHARED.equals(state)) {
-	        Toast.makeText(MainActivity.this, R.string.file_readonly_toast, Toast.LENGTH_LONG).show();
-	    } else {
-	    	Toast.makeText(MainActivity.this, R.string.file_no_sdcard, Toast.LENGTH_LONG).show();
-	    }
+					}
+				}
+				Log.d(TAG, "File saved in " + path + ".");
+			}
+		} else if (Environment.MEDIA_SHARED.equals(state)) {
+			Toast.makeText(MainActivity.this, R.string.file_readonly_toast,
+					Toast.LENGTH_LONG).show();
+		} else {
+			Toast.makeText(MainActivity.this, R.string.file_no_sdcard,
+					Toast.LENGTH_LONG).show();
+		}
 	}
 
 	private void openFile(String name) {
-		FileInputStream fis = null; 
-        InputStreamReader isr = null;
-        BufferedReader br = null;
-        StringBuilder content = new StringBuilder();
-	   	try{ 
-           fis = new FileInputStream(name);  
-           isr = new InputStreamReader(fis);
-           br = new BufferedReader(isr);
-           String line;
-           while ((line = br.readLine()) != null) {
-                content.append(line).append("\n");
-              }
-          
-          } catch (Exception e) {
-        	  Toast.makeText(MainActivity.this, R.string.file_read_fail, Toast.LENGTH_LONG).show();
-          } finally {
-        	  try {
-					br.close();
-				} catch (IOException e) {
-					e.printStackTrace();
-				}
-          }
-        Log.d(TAG,"Sources imported from " + name + ".");
-        String[] parsed_source = parse(content.substring(0, content.length()-1));
-		int last_panel_empty = (((EditText) findViewById(10*(editPanel_number-1) + EDITTEXT)).getText().toString().equals("")?1:0); 
-        for(String panel: parsed_source){
-        	if (!(panel = panel.trim()).equals("")){
-        		int current = editPanel_number - last_panel_empty;
-        		addEditPanel(current-1);
-        		((EditText) findViewById(10*current + EDITTEXT)).setText(panel);	
-        	}
-        }
+		FileInputStream fis = null;
+		InputStreamReader isr = null;
+		BufferedReader br = null;
+		StringBuilder content = new StringBuilder();
+		try {
+			fis = new FileInputStream(name);
+			isr = new InputStreamReader(fis);
+			br = new BufferedReader(isr);
+			String line;
+			while ((line = br.readLine()) != null) {
+				content.append(line).append("\n");
+			}
+		} catch (Exception e) {
+			Toast.makeText(MainActivity.this, R.string.file_read_fail,
+					Toast.LENGTH_LONG).show();
+		} finally {
+			try {
+				br.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+		editor.setText(content);
+		Log.d(TAG, "Sources imported from " + name + ".");
 	}
-	
-	private void menuSave(){
+
+	private void menuSave() {
 		Intent intent = new Intent(MainActivity.this, FileSave.class);
 		intent.putExtra("previous_filename", fileName);
 		startActivityForResult(intent, FILE_NAME);
 	}
-	
-	private void menuOpen(){
+
+	private void menuOpen() {
 		String state = Environment.getExternalStorageState();
 		if (Environment.MEDIA_MOUNTED.equals(state)) {
-	    	String path = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator + "ocaml";
-	    	File file = new File(path);
-	    	if(!file.isDirectory() || file.list().length == 0){
-	    		Toast.makeText(MainActivity.this, R.string.file_directory_not_found, Toast.LENGTH_LONG).show();
-	    	} else {
-	    		Intent intent = new Intent(MainActivity.this, FileOpen.class);
-	    		intent.putExtra("path", path);
-	    		startActivityForResult(intent, OPEN_FILE);
-	    	}
-	    } else if (Environment.MEDIA_SHARED.equals(state)) {
-	        Toast.makeText(MainActivity.this, R.string.file_readonly_toast, Toast.LENGTH_LONG).show();
-	    } else {
-	    	Toast.makeText(MainActivity.this, R.string.file_no_sdcard, Toast.LENGTH_LONG).show();
-	    }
-	}
-	
-	protected void onActivityResult(int requestCode, int result, Intent intent){
-		switch(requestCode){
-			case FILE_NAME:
-				if(result == Activity.RESULT_OK){
-					String name = intent.getExtras().getString("fileName");
-					
-					fileName = name;
-					saveFile(name, false);
-				} else {
-					Toast.makeText(MainActivity.this, R.string.file_not_saved, Toast.LENGTH_LONG).show();
-				}
-				break;
-			case OVERWRITE:
-				if(result == Activity.RESULT_OK){
-					saveFile(fileName, true);
-				} else {
-					Toast.makeText(MainActivity.this, R.string.file_not_saved, Toast.LENGTH_LONG).show();
-				}
-				break;
-			case OPEN_FILE:
-				if(result== Activity.RESULT_OK){
-					String file = intent.getExtras().getString("file");
-					openFile(file);
-				}
-				break;
+			String path = Environment.getExternalStorageDirectory()
+					.getAbsolutePath() + File.separator + "ocaml";
+			File file = new File(path);
+			if (!file.isDirectory() || file.list().length == 0) {
+				Toast.makeText(MainActivity.this,
+						R.string.file_directory_not_found, Toast.LENGTH_LONG)
+						.show();
+			} else {
+				Intent intent = new Intent(MainActivity.this, FileOpen.class);
+				intent.putExtra("path", path);
+				startActivityForResult(intent, OPEN_FILE);
+			}
+		} else if (Environment.MEDIA_SHARED.equals(state)) {
+			Toast.makeText(MainActivity.this, R.string.file_readonly_toast,
+					Toast.LENGTH_LONG).show();
+		} else {
+			Toast.makeText(MainActivity.this, R.string.file_no_sdcard,
+					Toast.LENGTH_LONG).show();
 		}
 	}
-	
+
+	protected void onActivityResult(int requestCode, int result, Intent intent) {
+		switch (requestCode) {
+		case FILE_NAME:
+			if (result == Activity.RESULT_OK) {
+				String name = intent.getExtras().getString("fileName");
+
+				fileName = name;
+				saveFile(name, false);
+			} else {
+				Toast.makeText(MainActivity.this, R.string.file_not_saved,
+						Toast.LENGTH_LONG).show();
+			}
+			break;
+		case OVERWRITE:
+			if (result == Activity.RESULT_OK) {
+				saveFile(fileName, true);
+			} else {
+				Toast.makeText(MainActivity.this, R.string.file_not_saved,
+						Toast.LENGTH_LONG).show();
+			}
+			break;
+		case OPEN_FILE:
+			if (result == Activity.RESULT_OK) {
+				String file = intent.getExtras().getString("file");
+				openFile(file);
+			}
+			break;
+		}
+	}
+
 	@Override
- 	public boolean onCreateOptionsMenu(Menu menu) { 
+	public boolean onCreateOptionsMenu(Menu menu) {
 		super.onCreateOptionsMenu(menu);
-		
-		menu.add(Menu.NONE, MENU_OPEN, Menu.NONE, R.string.menu_open)
-			.setIcon(R.drawable.ic_menu_archive);
-		menu.add(Menu.NONE, MENU_SAVE, Menu.NONE, R.string.menu_save)
-			.setIcon(R.drawable.ic_menu_save);
+
+		menu.add(Menu.NONE, MENU_OPEN, Menu.NONE, R.string.menu_open).setIcon(
+				R.drawable.ic_menu_archive);
+		menu.add(Menu.NONE, MENU_SAVE, Menu.NONE, R.string.menu_save).setIcon(
+				R.drawable.ic_menu_save);
 		menu.add(Menu.NONE, MENU_CLEAR, Menu.NONE, R.string.menu_clear)
-			.setIcon(R.drawable.ic_menu_clear_playlist);
+				.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);
-		
+				.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;
 	}
-	
+
 	@Override
-	public boolean onOptionsItemSelected(MenuItem item) { 
+	public boolean onOptionsItemSelected(MenuItem item) {
 		switch (item.getItemId()) {
 		case MENU_OPEN:
 			menuOpen();
 			return true;
 		case MENU_SAVE:
-			menuSave();;
+			menuSave();
+			;
 			return true;
 		case MENU_CLEAR:
 			clear();
 			startActivity(intent_about);
 			return true;
 		case MENU_QUIT:
-			FileOutputStream fos = null;;
+			FileOutputStream fos = null;
+			;
 			try {
 				fos = openFileOutput("autosave", Context.MODE_PRIVATE);
-				fos.write(merge().getBytes());
+				fos.write(editor.getText().toString().getBytes());
 				fos.close();
 			} catch (FileNotFoundException e) {
 				e.printStackTrace();
 			return super.onOptionsItemSelected(item);
 		}
 	}
-	
-	private Runnable outputUpdaterTask = new Runnable() {
 
-		public void run() {
-			// takes the lock, updates the outview, and says the output is up-to-date
-			synchronized(lock){
-				if(!output_upToDate){
-					outView.setText(Html.fromHtml(output_text.toString()));
-					//outView.postInvalidate();
-			        /*scrollView_toplevel.clearAnimation();
-			        scrollView_toplevel.smoothScrollTo(0, outView.getHeight()); */
-					scrollView_toplevel.requ
-					output_upToDate = true;
-					Log.v(TAG, "bip!");
-				}
-			}
-			outputUpdater.postDelayed(this, REFRESH_INTERVAL);
+	/*
+	 * private Runnable outputUpdaterTask = new Runnable() {
+	 * 
+	 * public void run() { // takes the lock, updates the outview, and says the
+	 * output is up-to-date synchronized(lock){ if(!output_upToDate){
+	 * outView.setText(Html.fromHtml(output_text.toString()));
+	 * //outView.postInvalidate(); //scrollView_toplevel.clearAnimation();
+	 * //scrollView_toplevel.smoothScrollTo(0, outView.getHeight());
+	 * //scrollView_toplevel.requ output_upToDate = true; Log.v(TAG, "bip!"); }
+	 * } outputUpdater.postDelayed(this, REFRESH_INTERVAL); }
+	 * 
+	 * };
+	 */
+
+	private class BackThread extends AsyncTask<Void, String, Void> {
+
+		private PrintWriter out;
+		private InputStream in = null;
+
+		public PrintWriter getOutput() {
+			return out;
 		}
 
-	};
-	
-	private class BackThread extends AsyncTask<Void,String,Void> { 
-				
 		@Override
-		protected void onPreExecute(){
+		protected void onPreExecute() {
 			try {
+
+				OcamlTop toplevel = null;
 				Object[] tab = (Object[]) getLastNonConfigurationInstance();
-				if(tab == null) {
+				if (tab == null) {
 					try {
 						toplevel = new OcamlTop(MainActivity.this);
 					} catch (Exception e) {
-						output_text.delete(0, output_text.length());
-						println(getString(R.string.toplevel_start_fail),FROM_TOPLEVEL);
+						output_text.clear();
+						println(getString(R.string.toplevel_start_fail),
+								FROM_TOPLEVEL, true);
 					}
-					Log.d(TAG,"New Toplevel created");
+					Log.d(TAG, "New Toplevel created");
+				} else {
+					toplevel = (OcamlTop) tab[0];
+					Log.d(TAG, "Old Toplevel found");
 				}
-				else {
-					toplevel = (OcamlTop) tab[0];
-					Log.d(TAG,"Old Toplevel found");
-				}
-				if (toplevel == null || toplevel.stream == null){
-					println(getString(R.string.toplevel_start_fail),FROM_TOPLEVEL);
-					Log.e(TAG,"Unable to start the toplevel");
+				if (toplevel == null || toplevel.stream == null) {
+					println(getString(R.string.toplevel_start_fail),
+							FROM_TOPLEVEL, true);
+					Log.e(TAG, "Unable to start the toplevel");
 				} else {
 					in = toplevel.stream.getInputStream();
 					out = new PrintWriter(new OutputStreamWriter(
 							toplevel.stream.getOutputStream(), "utf-8"));
+					MainActivity.this.out = out;
 				}
-				
-				
 
-				
 			} catch (IOException e) {
 				Log.e(TAG, "error in main", e);
 			}
 		}
-		
+
 		@Override
 		protected Void doInBackground(Void... params) {
-			if (in == null){
-				output_text.delete(0, output_text.length());
-				println(getString(R.string.toplevel_start_fail),FROM_TOPLEVEL);
+			if (in == null) {
+				runOnUiThread(new Runnable() {
+
+					public void run() {
+						output_text.clear();
+						println(getString(R.string.toplevel_start_fail),
+								FROM_TOPLEVEL, true);
+					}
+				});
 			} else {
-			
+
 				try {
 					while (true) {
 						int i = in.read();
-						if(i==-1) {
+						if (i == -1) {
 							break;
 						}
 						int len = in.available();
-						byte[] b = new byte[len+1];
-						b[0] = (byte)(i <= 127 ? i : i - 256);
+						byte[] b = new byte[len + 1];
+						b[0] = (byte) (i <= 127 ? i : i - 256);
 						in.read(b, 1, len);
-						publishProgress(new String(b,"utf-8"));
-											 
+						publishProgress(new String(b, "utf-8"));
 					}
-				} catch (IOException e) {	
-					Log.e(TAG, "Datas has been lost", e); 
-					Toast.makeText(MainActivity.this, R.string.data_lost, Toast.LENGTH_LONG).show();
+				} catch (IOException e) {
+					Log.e(TAG, "Datas has been lost", e);
+					Toast.makeText(MainActivity.this, R.string.data_lost,
+							Toast.LENGTH_LONG).show();
 				}
 			}
-			return null;  
+			return null;
 		}
-			
+
 		@Override
-		protected void onProgressUpdate(String... strings){
-			println(strings[0],FROM_TOPLEVEL);
-			Log.v(TAG,strings[0]);
+		protected void onProgressUpdate(String... strings) {
+			parseAndPrint(strings[0], FROM_TOPLEVEL);
+			Log.v(TAG, strings[0]);
 		}
 	}
-	
-		
-	
 
-	
 }

src/fr/vernoux/ocaml/OutputAdapter.java

+package fr.vernoux.ocaml;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.text.Html;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+public class OutputAdapter extends BaseAdapter {
+	
+	private final static String LOG = "OutputAdapter";
+	
+	private ArrayList<OutputLine> output_text;
+	private Context context;
+	
+	public OutputAdapter(Context context, ArrayList<OutputLine> output_text2) {
+		this.output_text = output_text2;
+		this.context = context;
+	}
+
+	public int getCount() {
+		if(output_text != null)
+			return output_text.size();
+		else
+			return 0;
+	}
+
+	public Object getItem(int arg0) {
+		if(output_text == null)
+			return null;
+		else
+			return output_text.get(arg0);
+	}
+
+	public long getItemId(int arg0) {
+		return Long.valueOf(arg0);
+	}
+
+	public View getView(int position, View convertView, ViewGroup parent) {
+				
+		TextView ll = (TextView) convertView;
+		if(convertView == null){
+			LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+			ll = (TextView) vi.inflate(R.layout.output_sublayout, null);
+		}
+		String output_line = output_text.get(position).getText();
+		System.out.println(output_line);
+		
+        if (output_line != null) {
+        	TextView view = (TextView) ll.findViewById(R.id.text);
+        	view.setText(Html.fromHtml(output_line));
+        } else {
+        	Log.e(LOG, String.format("Tried to adapt item %d which is null", position));
+        }
+        return ll;
+	}
+}

src/fr/vernoux/ocaml/OutputLine.java

+package fr.vernoux.ocaml;
+
+public class OutputLine {
+	
+	public static final String TOPLEVEL_START_TAG = "";
+	public static final String TOPLEVEL_END_TAG = "";
+	public static final String USER_START_TAG = "<b>";
+	public static final String USER_END_TAG = "</b>";
+	
+	private String text = "";
+	private int origin;
+	
+	public OutputLine(String text, int origin){
+		addText(text, origin);
+		this.origin = origin;
+	}
+
+	public String getText() {
+		return text;
+	}
+
+	public void addText(String text, int origin) {
+		if(origin == MainActivity.FROM_USER){
+			this.text = this.text + USER_START_TAG + 
+					text.replace("<", "&lt;").replace("\n", "<br />") + 
+					USER_END_TAG;
+		} else {
+			this.text = this.text + TOPLEVEL_START_TAG + 
+					text.replace("<", "&lt;").replace("\n", "<br />") + 
+					TOPLEVEL_END_TAG;
+		}
+	}
+
+	public int getOrigin() {
+		return origin;
+	}
+
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.