package org.ruboto.irb; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.Writer; import java.util.ArrayList; import java.util.List; import org.jruby.embed.io.WriterOutputStream; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.os.Process; import android.os.Environment; import android.text.util.Linkify; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ScrollView; import android.widget.TabHost; import android.widget.TabHost.OnTabChangeListener; import android.widget.TabWidget; import android.widget.TextView; import android.widget.Toast; import android.view.View.OnClickListener; import android.widget.Button; import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.Dialog; import android.content.DialogInterface; import android.os.Environment; import android.util.Log; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.TextView; import android.widget.Toast; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.FileReader; import org.ruboto.JRubyAdapter; public class IRB extends IRBEntryPointActivity implements OnItemClickListener, OnTabChangeListener { ////////////////////////////////////////////////////////////// // Stores names of traversed directories ArrayList<String> str = new ArrayList<String>(); // Check if the first level of the directory structure is the one showing private Boolean firstLvl = true; private Item[] fileList; private File path = new File(Environment.getExternalStorageDirectory() + ""); private String chosenFile; private static final int DIALOG_LOAD_FILE = 1000; ListAdapter adapter1; ////////////////////////////////////////////////////////////// public static final String TAG = "Ruboto-IRB"; public static final String SDCARD_SCRIPTS_DIR = "/sdcard/jruby"; private TabHost tabs; private TabWidget tabWidget; private final Handler handler = new Handler(); private PrintStream printStream; private long timeBackPressed = 0; /* IRB_Tab Elements */ public static TextView currentIrbOutput; private TextView irbOutput; private HistoryEditText irbInput; /* Edit_Tab Elements */ private LineNumberEditText sourceEditor; private TextView fnameTextView; private IRBScript currentScript; /* Script_Tab Elements */ private ArrayAdapter<String> adapter; private List<String> scripts; /* Tab identifiers */ private static final int IRB_TAB = 0; private static final int EDITOR_TAB = 1; private static final int SCRIPTS_TAB = 2; /* Menu option identifiers */ private static final int SAVE_MENU = 1; private static final int RUN_MENU = 2; private static final int NEW_MENU = 3; private static final int HISTORY_MENU = 4; private static final int ABOUT_MENU = 5; private static final int RESCAN_MENU = 6; private static final int RELOAD_DEMOS_MENU = 7; private static final int CLEAR_IRB_MENU = 8; private static final int EDIT_IRB_MENU = 9; private static final int MAX_SCREEN_MENU = 10; private static final int LINE_NUMBERS_MENU = 11; private static final int GOTO_MENU = 12; private static final int IMPORT_MENU = 13; /* Context menu option identifiers for script list */ private static final int EDIT_MENU = 20; private static final int EXECUTE_MENU = 21; private static final int DELETE_MENU = 22; private static final int SHARE_MENU = 23; private static final String DEMO_SCRIPTS = "demo-scripts"; /********************************************************************************************* * * Setup */ // Needed because called during startup public void initializeRuboto() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); JRubyAdapter.setLocalVariableBehavior("PERSISTENT"); uiSetup(); } @Override public void onBackPressed() { if (System.currentTimeMillis() - timeBackPressed < 5000) { finish(); } else { Toast.makeText(this, "Press back again to exit.", Toast.LENGTH_SHORT).show(); timeBackPressed = System.currentTimeMillis(); } } private boolean configuredIRB = false; protected void fireRubotoActivity() { if (configuredIRB) return; JRubyAdapter.put("$irb", this); // if(getScriptInfo().isLoaded()) return; super.fireRubotoActivity(); configScriptsDir(true); configuredIRB = true; } public boolean rubotoAttachable() { return false; } private void uiSetup() { SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE); if (prefs.getBoolean("HideTitle", false)) requestWindowFeature(Window.FEATURE_NO_TITLE); if (prefs.getBoolean("Fullscreen", false)) getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.main); tabs = (TabHost) findViewById(R.id.tabhost); tabs.setOnTabChangedListener(this); tabs.setup(); tabWidget = (TabWidget) findViewById(android.R.id.tabs); tabWidget.setVisibility(prefs.getBoolean("HideTabs", false) ? View.GONE : View.VISIBLE); irbSetUp(); printStream = new PrintStream( new WriterOutputStream(new Writer() { @Override public void write(final char[] chars, final int start, final int length) throws IOException { IRB.this.runOnUiThread(new Runnable() { public void run() { IRB.appendToIRB(new String(chars, start, length)); } }); } @Override public void flush() throws IOException { // no buffer } @Override public void close() throws IOException { // meaningless } })); JRubyAdapter.setOutputStream(printStream); irbOutput.append(">> "); configScriptsDir(false); editorSetUp(); scriptsListSetUp(); Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) { try { BufferedWriter buffer = new BufferedWriter(new FileWriter(IRBScript.getDir() + "/error.log")); buffer.write(e.getMessage() + "\n"); for (java.lang.StackTraceElement ste : e.getStackTrace()) { buffer.append(ste.toString() + "\n"); } buffer.close(); } catch (IOException ioe) { } System.exit(0); } } ); Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) { IRB.appendToIRB(e.getMessage() + "\n"); for (java.lang.StackTraceElement ste : e.getStackTrace()) { IRB.appendToIRB(ste.toString() + "\n"); } IRB.appendToIRB("\n>> "); } } ); autoLoadScript(); } private void irbSetUp() { tabs.addTab(tabs .newTabSpec("irb") .setContent(R.id.tab1) .setIndicator(getString(R.string.IRB_Tab), getResources().getDrawable(R.drawable.ic_tab_irb))); irbInput = (HistoryEditText) findViewById(R.id.irb_edittext); irbOutput = (TextView) findViewById(R.id.irb_textview); irbOutput .setMovementMethod(new android.text.method.ScrollingMovementMethod()); currentIrbOutput = irbOutput; irbInput.setLineListener(new HistoryEditText.LineListener() { public void onNewLine(String rubyCode) { irbOutput.append(rubyCode + "\n"); try { irbOutput.append("=> "); JRubyAdapter.setScriptFilename("eval"); irbOutput.append(runScriptlet(rubyCode)); } catch (RuntimeException e) { reportExecption(e); } irbOutput.append("\n>> "); irbInput.setText(""); } }); File err = new File(IRBScript.getDir() + "/error.log"); try { BufferedReader buffer = new BufferedReader(new FileReader(err), 8192); irbOutput.append("Previous run exited:\n"); while (true) { String line = buffer.readLine(); if (line == null) break; irbOutput.append(line); irbOutput.append("\n"); } buffer.close(); err.delete(); } catch (java.io.FileNotFoundException fe) { } catch (java.io.IOException ioe) { } } private void editorSetUp() { tabs.addTab(tabs .newTabSpec("editor") .setContent(R.id.tab2) .setIndicator(getString(R.string.Editor_Tab), getResources().getDrawable(R.drawable.ic_tab_editor))); sourceEditor = (LineNumberEditText) findViewById(R.id.source_editor); fnameTextView = (TextView) findViewById(R.id.fname_textview); final android.view.GestureDetector gestureDetector = new android.view.GestureDetector(new FlingGestureListener()); sourceEditor.setOnTouchListener(new android.view.View.OnTouchListener() { public boolean onTouch(android.view.View view,android.view.MotionEvent event) { return gestureDetector.onTouchEvent(event); } }); editScript(IRBScript.UNTITLED_RB, false); } private void scriptsListSetUp() { tabs.addTab(tabs .newTabSpec("scripts") .setContent(R.id.tab3) .setIndicator(getString(R.string.Scripts_Tab), getResources().getDrawable(R.drawable.ic_tab_scripts))); ListView scriptsList = (ListView) findViewById(R.id.scripts_listview); scripts = IRBScript.list(); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, scripts); scriptsList.setAdapter(adapter); TextView emptyView = new TextView(this); emptyView.setText(R.string.No_scripts); scriptsList.setEmptyView(emptyView); scriptsList.setOnItemClickListener(this); registerForContextMenu(scriptsList); } /* * Static method needed to get to the current irbOutput after the Activity * reloads */ public static void appendToIRB(String string) { currentIrbOutput.append(string); } /* Loads the script specified in the Intent (if supplied) */ public void autoLoadScript() { if (getIntent().getData() != null) { IRBScript script = IRBScript.fromURL(getIntent().getData() .toString()); if (script != null) editScript(script, true); } } /* Common method for copying stacktrace to irbOutput */ private void reportExecption(Exception e) { // TODO: Compact or highlight some levels for (java.lang.StackTraceElement ste : e.getStackTrace()) { irbOutput.append(ste.toString() + "\n"); } } private String runScriptlet(String code) { Object rtn = JRubyAdapter.runScriptlet(code); return (String)JRubyAdapter.runRubyMethod(String.class, rtn, "inspect"); } /********************************************************************************************* * * TabHost Listener */ public void onTabChanged(String tabId) { if (tabId.equals("scripts")) { ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) .hideSoftInputFromWindow(tabs.getWindowToken(), 0); if (IRBScript.scriptsDirChanged()) scanScripts(); } } /********************************************************************************************* * * Menu Setup */ /* Set up context menus */ @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, SAVE_MENU, 0, R.string.Menu_save).setIcon( android.R.drawable.ic_menu_save); menu.add(0, RUN_MENU, 0, R.string.Menu_run).setIcon( R.drawable.ic_menu_play); menu.add(0, NEW_MENU, 0, R.string.Menu_new).setIcon( android.R.drawable.ic_menu_add); menu.add(0, HISTORY_MENU, 0, R.string.Menu_history).setIcon( android.R.drawable.ic_menu_recent_history); menu.add(0, ABOUT_MENU, 0, R.string.Menu_about).setIcon( android.R.drawable.ic_menu_info_details); // menu.add(0, RESCAN_MENU, 0, R.string.Menu_rescan); menu.add(0, RELOAD_DEMOS_MENU, 0, R.string.Menu_reload); menu.add(0, CLEAR_IRB_MENU, 0, R.string.Menu_clear_irb); menu.add(0, EDIT_IRB_MENU, 0, R.string.Menu_edit_irb); menu.add(0, MAX_SCREEN_MENU, 0, R.string.Menu_max_screen); menu.add(0, LINE_NUMBERS_MENU, 0, R.string.Menu_line_numbers); menu.add(0, GOTO_MENU, 0, R.string.Menu_goto); menu.add(0, IMPORT_MENU, 0, R.string.Menu_import); return true; } /* Called when a menu item clicked */ @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { SharedPreferences prefs = null; SharedPreferences.Editor prefsEditor = null; switch (item.getItemId()) { case SAVE_MENU: saveEditorScript(); return true; case RUN_MENU: runEditorScript(); return true; case NEW_MENU: editScript(IRBScript.UNTITLED_RB, true); return true; case HISTORY_MENU: editScript( new IRBScript(IRBScript.UNTITLED_RB, irbInput.getHistoryString()), true); return true; case ABOUT_MENU: aboutDialog(); return true; case RESCAN_MENU: scanScripts(); tabs.setCurrentTab(SCRIPTS_TAB); return true; case RELOAD_DEMOS_MENU: Toast.makeText(this, recopyDemoScripts(DEMO_SCRIPTS, IRBScript.getDirFile()), Toast.LENGTH_SHORT).show(); scanScripts(); tabs.setCurrentTab(SCRIPTS_TAB); return true; case CLEAR_IRB_MENU: irbOutput.setText(">> "); tabs.setCurrentTab(IRB_TAB); return true; case EDIT_IRB_MENU: editScript(new IRBScript(IRBScript.UNTITLED_RB, irbOutput.getText() .toString()), true); tabs.setCurrentTab(EDITOR_TAB); return true; case MAX_SCREEN_MENU: prefs = getPreferences(Context.MODE_PRIVATE); prefsEditor = prefs.edit(); tabWidget .setVisibility(tabWidget.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE); if (prefs.getBoolean("Fullscreen", false)) { getWindow().clearFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN); } else { getWindow() .addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); } prefsEditor.putBoolean("HideTabs", tabWidget.getVisibility() == View.GONE); prefsEditor.putBoolean("Fullscreen", !prefs.getBoolean("Fullscreen", false)); prefsEditor.putBoolean("HideTitle", !prefs.getBoolean("HideTitle", false)); prefsEditor.commit(); displayDialog("Title Visibility Change", "Reorient the screen for this to take effect.", null, null); return true; case LINE_NUMBERS_MENU: sourceEditor.setShowLineNumbers(!sourceEditor.getShowLineNumbers()); tabs.setCurrentTab(EDITOR_TAB); return true; case GOTO_MENU: tabs.setCurrentTab(EDITOR_TAB); gotoDialog(); return true; case IMPORT_MENU: loadFileList(); showDialog(DIALOG_LOAD_FILE); Log.d(TAG, path.getAbsolutePath()); return true; } return super.onMenuItemSelected(featureId, item); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// public String readfiles(String path) { String aBuffer = ""; try { File myFile = new File(path); FileInputStream fIn = new FileInputStream(myFile); BufferedReader myReader = new BufferedReader( new InputStreamReader(fIn)); String aDataRow = ""; // String aBuffer = ""; while ((aDataRow = myReader.readLine()) != null) { aBuffer += aDataRow + "\n"; } // txtData.setText(aBuffer); myReader.close(); Toast.makeText(getBaseContext(), "Done reading SD 'mysdfile.txt'", Toast.LENGTH_SHORT).show(); } catch (Exception e) { Toast.makeText(getBaseContext(), e.getMessage(), Toast.LENGTH_SHORT).show(); } return aBuffer; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// public void loadFileList() { try { path.mkdirs(); } catch (SecurityException e) { Log.e(TAG, "unable to write on the sd card "); } // Checks whether path exists if (path.exists()) { FilenameFilter filter = new FilenameFilter() { @Override public boolean accept(File dir, String filename) { File sel = new File(dir, filename); // Filters based on whether the file is hidden or not return (sel.isFile() || sel.isDirectory()) && !sel.isHidden(); } }; String[] fList = null; try{ fList = path.list(filter); fileList = new Item[fList.length]; } catch (Exception e) { Toast.makeText(IRB.this,"No SD card",1).show(); return; } for (int i = 0; i < fList.length; i++) { fileList[i] = new Item(fList[i], R.drawable.file_icon); // Convert into file path File sel = new File(path, fList[i]); // Set drawables if (sel.isDirectory()) { fileList[i].icon = R.drawable.directory_icon; Log.d("DIRECTORY", fileList[i].file); } else { Log.d("FILE", fileList[i].file); } } if (!firstLvl) { Item temp[] = new Item[fileList.length + 1]; for (int i = 0; i < fileList.length; i++) { temp[i + 1] = fileList[i]; } temp[0] = new Item("Up", R.drawable.directory_up); fileList = temp; } } else { Log.e(TAG, "path does not exist"); } adapter1 = new ArrayAdapter<Item>(this, android.R.layout.select_dialog_item, android.R.id.text1, fileList) { @Override public View getView(int position, View convertView, ViewGroup parent) { // creates view View view = super.getView(position, convertView, parent); TextView textView = (TextView) view .findViewById(android.R.id.text1); // put the image on the text view textView.setCompoundDrawablesWithIntrinsicBounds( fileList[position].icon, 0, 0, 0); // add margin between image and text (support various screen // densities) int dp5 = (int) (5 * getResources().getDisplayMetrics().density + 0.5f); textView.setCompoundDrawablePadding(dp5); return view; } }; } private class Item { public String file; public int icon; public Item(String file, Integer icon) { this.file = file; this.icon = icon; } @Override public String toString() { return file; } } @Override public Dialog onCreateDialog(int id) { Dialog dialog = null; AlertDialog.Builder builder = new Builder(this); if (fileList == null) { Log.e(TAG, "No files loaded"); dialog = builder.create(); return dialog; } switch (id) { case DIALOG_LOAD_FILE: builder.setTitle("Choose your file"); builder.setAdapter(adapter1, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { chosenFile = fileList[which].file; File sel = new File(path + "/" + chosenFile); if (sel.isDirectory()) { firstLvl = false; // Adds chosen directory to list str.add(chosenFile); fileList = null; path = new File(sel + ""); loadFileList(); removeDialog(DIALOG_LOAD_FILE); showDialog(DIALOG_LOAD_FILE); Log.d(TAG, path.getAbsolutePath()); } // Checks if 'up' was clicked else if (chosenFile.equalsIgnoreCase("up") && !sel.exists()) { // present directory removed from list String s = str.remove(str.size() - 1); // path modified to exclude present directory path = new File(path.toString().substring(0, path.toString().lastIndexOf(s))); fileList = null; // if there are no more directories in the list, then // its the first level if (str.isEmpty()) { firstLvl = true; } loadFileList(); removeDialog(DIALOG_LOAD_FILE); showDialog(DIALOG_LOAD_FILE); Log.d(TAG, path.getAbsolutePath()); } // File picked else { int dot = chosenFile.lastIndexOf("."); String ext = chosenFile.substring(dot + 1); if(ext.equals("txt") || ext.equals("rb") || ext.equals("script") ) { neweditScript(readfiles(path + "/" + chosenFile),true,chosenFile); } else Toast.makeText(IRB.this,"Not supported extension type" + ext,1).show(); // finish(); // return; } } }); break; } dialog = builder.show(); return dialog; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Set up context menus for script list */ @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); menu.add(0, EDIT_MENU, 0, R.string.Menu_edit); menu.add(0, EXECUTE_MENU, 0, R.string.Menu_run); menu.add(0, DELETE_MENU, 0, R.string.Menu_delete); menu.add(0, SHARE_MENU, 0, R.string.Menu_share); } /* Called when an entry in the Script List is long clicked */ public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case EDIT_MENU: editScript( scripts.get(((AdapterContextMenuInfo) item.getMenuInfo()).position), true); return true; case EXECUTE_MENU: executeScript(scripts.get(((AdapterContextMenuInfo) item .getMenuInfo()).position)); return true; case DELETE_MENU: confirmDelete(scripts.get(((AdapterContextMenuInfo) item .getMenuInfo()).position)); return true; case SHARE_MENU: shareScript(scripts.get(((AdapterContextMenuInfo) item .getMenuInfo()).position)); default: return false; } } /* Called when an entry in the Script List is clicked */ public void onItemClick(AdapterView<?> av, View v, int pos, long id) { editScript(scripts.get(pos), true); } /************************************************************************************ * * Script actions */ /* Reload the list of scripts */ private void scanScripts() { try { scripts = IRBScript.list(scripts); adapter.notifyDataSetChanged(); } catch (SecurityException se) { Toast.makeText(this, "Could not create " + IRBScript.getDir(), Toast.LENGTH_SHORT); } } /* Run the script currently in the editor */ private void runEditorScript() { irbOutput.append("[Running editor script (" + currentScript.getName() + ")]\n"); try { irbOutput.append("=> "); JRubyAdapter.setScriptFilename(currentScript.getName()); irbOutput.append(runScriptlet(sourceEditor.getText().toString())); } catch (RuntimeException e) { reportExecption(e); } irbOutput.append("\n>> "); tabs.setCurrentTab(IRB_TAB); } /* Save the script currently in the editor */ private void saveEditorScript() { try { currentScript = new IRBScript(fnameTextView.getText().toString()); currentScript.setContents(sourceEditor.getText().toString()).save(); scanScripts(); Toast.makeText(this, "Saved " + currentScript.getName(), Toast.LENGTH_SHORT).show(); tabs.setCurrentTab(SCRIPTS_TAB); } catch (IOException e) { Toast.makeText(this, "Could not write " + currentScript.getName(), Toast.LENGTH_SHORT).show(); } } /* Load script into editor and switch to editor view */ private void editScript(IRBScript script, Boolean switchTab) { try { currentScript = script; fnameTextView.setText(script.getName()); sourceEditor.setText(script.getFile().exists() ? script .getContents() : ""); //Toast.makeText(IRB.this,script.getFile().exists() ? script.getContents() : "",1).show(); sourceEditor.scrollTo(0, 0); if (switchTab) tabs.setCurrentTab(EDITOR_TAB); } catch (IOException e) { Toast.makeText(this, "Could not open " + script.getName(), Toast.LENGTH_SHORT).show(); } } public void neweditScript(String content, Boolean switchTab,String ChosenFileName){ fnameTextView.setText(ChosenFileName); sourceEditor.setText(content); sourceEditor.scrollTo(0,0); if (switchTab) tabs.setCurrentTab(EDITOR_TAB); } private void editScript(String name, Boolean switchTab) { editScript(new IRBScript(name), switchTab); } /* Execute the script and switch to IRB tab */ private void executeScript(String name) { try { irbOutput.append("[Running " + name + "]\n"); irbOutput.append("=> "); irbOutput.append(new IRBScript(name).execute()); } catch (IOException e) { Toast.makeText(this, "Could not open " + name, Toast.LENGTH_SHORT) .show(); } catch (RuntimeException e) { reportExecption(e); } irbOutput.append("\n>> "); tabs.setCurrentTab(IRB_TAB); } /* Delete script and reload scripts list */ private void deleteScript(String fname) { if (new IRBScript(fname).delete()) { Toast.makeText(this, fname + " deleted!", Toast.LENGTH_SHORT) .show(); } else { Toast.makeText(this, "Could not delete " + fname, Toast.LENGTH_SHORT).show(); } scanScripts(); } private void shareScript(IRBScript script) { Intent i = new Intent(this,net.android.facebook.TestConnect.class); try { currentScript = script; // ScriptName = script.getName(); // ScriptContent=script.getFile().exists() ? script.getContents() : ""; i.putExtra("code",script.getFile().exists() ? script.getContents() : ""); i.putExtra("Sname",script.getName()); startActivity(i); } catch (IOException e) { Toast.makeText(this, "Could not share " + script.getName(), Toast.LENGTH_SHORT).show(); } } private void shareScript(String name) { shareScript(new IRBScript(name)); } /************************************************************************************ * * Dialogs */ /* * Generic dialogs */ private void displayDialog(String title, Object messageOrView, DialogInterface.OnClickListener positive, DialogInterface.OnClickListener negative) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(title); if (messageOrView instanceof String) { builder.setMessage((String) messageOrView); } else { builder.setView((View) messageOrView); } if (positive == null) { builder.setPositiveButton(R.string.Dialog_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { } }); } else { builder.setPositiveButton(R.string.Dialog_ok, positive); } if (negative != null) { builder.setNegativeButton(R.string.Dialog_cancel, negative); } builder.create().show(); } /* * Script deletion dialog */ private void confirmDelete(final String fname) { displayDialog("Confirm", "Delete " + fname + "?", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { deleteScript(fname); } }, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); } /* * About dialog */ private void aboutDialog() { ScrollView sv = new ScrollView(this); TextView tv = new TextView(this); tv.setPadding(5, 5, 5, 5); tv.setText(R.string.About_text); Linkify.addLinks(tv, Linkify.ALL); sv.addView(tv); displayDialog(getString(R.string.app_name) + " v " + getString(R.string.version_name), sv, null, null); } /* * Goto dialog */ private void gotoDialog() { final EditText et = new EditText(this); displayDialog("Go to", et, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { try { int i = Integer.valueOf(et.getText().toString()); sourceEditor.scrollTo(0, (i - 1) * sourceEditor.getLineHeight()); } catch (Exception e) { } } }, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); } /********************************************************************************************* * * Activity Results: Make activity result available to Ruby */ /* @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); JRubyAdapter.defineGlobalVariable("$last_activity_result", new ActivityResult(requestCode, resultCode, data)); } */ public static class ActivityResult { public int requestCode, resultCode; public Intent data; public ActivityResult(int req, int res, Intent dat) { requestCode = req; resultCode = res; data = dat; } } protected static String scriptsDirName(Activity context) { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { return Environment.getExternalStorageDirectory().getAbsolutePath() + "/jruby"; } else { return context.getFilesDir().getAbsolutePath() + "/scripts"; } } private void configScriptsDir(boolean checkForUpdate) { if (checkForUpdate) { JRubyAdapter.addLoadPath(IRB.scriptsDirName(this)); } else { IRBScript.setDir(IRB.scriptsDirName(this)); } if (!IRBScript.getDirFile().exists()) { // on first install init directory + copy sample scripts copyDemoScripts(DEMO_SCRIPTS, IRBScript.getDirFile()); } else { File from = new File(IRBScript.getDirFile(), "ruboto.rb"); if (from.exists()) removeOldRubotoScripts(); if (checkForUpdate && !checkVersionString()) { // Scripts exist but need updating confirmUpdate(); } } } private void copyDemoScripts(String from, File to) { IRBScript.getDirFile().mkdirs(); try { byte[] buffer = new byte[8192]; for (String f : getAssets().list(from)) { File dest = new File(to, f); if (dest.exists()) continue; Log.d(TAG, "copying file " + f); if (getAssets().list(from + "/" + f).length == 0) { InputStream is = getAssets().open(from + "/" + f); OutputStream fos = new BufferedOutputStream( new FileOutputStream(dest), 8192); int n; while ((n = is.read(buffer, 0, buffer.length)) != -1) fos.write(buffer, 0, n); is.close(); fos.close(); } else { dest.mkdir(); copyDemoScripts(from + "/" + f, dest); } } updateVersionString(); } catch (IOException iox) { Log.e(TAG, "error copying demo scripts", iox); } } public String recopyDemoScripts(String from, File to) { String rv = ""; try { byte[] buffer = new byte[8192]; for (String f : getAssets().list(from)) { File dest = new File(to, f); if (dest.exists()) { Log.d(TAG, "replacing file " + f); } else { Log.d(TAG, "copying file " + f); } if (getAssets().list(from + "/" + f).length == 0) { InputStream is = getAssets().open(from + "/" + f); OutputStream fos = new BufferedOutputStream( new FileOutputStream(dest), 8192); int n; while ((n = is.read(buffer, 0, buffer.length)) != -1) fos.write(buffer, 0, n); is.close(); fos.close(); rv += "\nCopied:" + f; } else { dest.mkdir(); rv += "\n" + recopyDemoScripts(from + "/" + f, dest); } } updateVersionString(); } catch (IOException iox) { Log.e(TAG, "error copying demo scripts", iox); rv = "Copy failed"; } return rv; } private boolean checkVersionString() { return getPreferences(Context.MODE_PRIVATE).getString( "Demo_scripts_version", "0").equals( getString(R.string.demo_scripts_version)); } private void updateVersionString() { if (!checkVersionString()) { SharedPreferences.Editor prefsEditor = getPreferences( Context.MODE_PRIVATE).edit(); prefsEditor.putString("Demo_scripts_version", getString(R.string.demo_scripts_version)); prefsEditor.commit(); } } private void confirmUpdate() { displayDialog("Update Scripts", getString(R.string.Script_update_text), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Toast.makeText( IRB.this, IRB.this.recopyDemoScripts(DEMO_SCRIPTS, IRBScript.getDirFile()), Toast.LENGTH_SHORT).show(); } }, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); } private void removeOldRubotoScripts() { displayDialog("Remove Ruboto Scripts", getString(R.string.Ruboto_remove_text), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { File from = new File(IRBScript.getDirFile(), "ruboto.rb"); if (from.exists()) from.renameTo(new File(IRBScript.getDirFile(), "old-ruboto.rb")); from = new File(IRBScript.getDirFile(), "ruboto"); if (from.exists()) from.renameTo(new File(IRBScript.getDirFile(), "old-ruboto")); } }, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); } /********************************************************************************************* * * Fling Listener */ class FlingGestureListener extends android.view.GestureDetector.SimpleOnGestureListener { private android.widget.Scroller scroller = null; //@scroller = android.widget.Scroller.new(@activity) private int x = 0; //@x = 0 FlingGestureListener() { super(); scroller = new android.widget.Scroller(IRB.this); } public boolean onDown(android.view.MotionEvent e) { if (scroller.isFinished()) return false; scroller.forceFinished(true); return true; } public boolean onFling(android.view.MotionEvent e1, android.view.MotionEvent e2, float velocityX, float velocityY) { if (Math.abs(velocityY) < android.view.ViewConfiguration.get(IRB.this).getScaledMinimumFlingVelocity()) return false; x = IRB.this.sourceEditor.getScrollX(); int max = IRB.this.sourceEditor.getLayout().getHeight() - IRB.this.sourceEditor.getHeight() + IRB.this.sourceEditor.getLineHeight(); scroller.fling(0, IRB.this.sourceEditor.getScrollY(), 0, 0 - (int)velocityY, x, x, 0, max); final Runnable run = new Runnable() { public void run() { if (scroller.isFinished() || !scroller.computeScrollOffset()) return; IRB.this.sourceEditor.scrollTo(x, scroller.getCurrY()); IRB.this.sourceEditor.post(this); } }; IRB.this.sourceEditor.post(run); return true; } } }