**This is an old revision of the document!** ----
====== About the script ====== * Purpose : This script is a multifunctional tool to do or show a lot of stuff * Author : [[https://plus.google.com/+LukasMorawietz|LM13]] * Current Version : 2.1 * Link : https://plus.google.com/115366157037831519359/posts/fQwfu5AUj5m * Download avialable! (Check repository) ====== Changelog ====== * Version 1.0 (20/7/2014): initial release in wiki * Version 1.1 (21/7/2014): replaced move item script with trianguloY's solution. * Version 1.2 (25/7/2014): replaced change home page with move pages to extend functionality, sorted choices on script-side * Version 1.2.1 (26/7/2014): added Intent to Item details * Version 1.3 (28/7/2014): fix: no touch data in swipe event, add resize, add save, add containers ID * Version 1.3.1 (31/8/2014): fix: Intent also for folders * Version 2.0 (14/9/2014): new UI, added comments, removed the easteregg, because it's not reachable through the new UI * Version 2.1 (24/9/2014): UI updated again, now selection is sorted into categorys, added import, export and autoformat scripts ====== How to use the script ====== * enable the script in any menu or event you want to run it ====== Current functionality ====== * Show Event related parameters * Show Container related parameters * Show Item related parameters * Attach/Detach all Items * Resize all detached items * Delete all Items * Move (a) specific page(s) to another position. This can be used to change the home page by selecting all items * Export Scripts * Import Script * Autoformat Script * Reset Tag * Reset Tool © by trianguloY * save all Layout changes //please report all bugs in the g+ community// ====== Script ====== <sxh javascript;> //import java classes LL.bindClass("android.app.AlertDialog"); LL.bindClass("android.content.DialogInterface"); LL.bindClass("android.widget.ExpandableListView"); LL.bindClass("android.widget.SimpleExpandableListAdapter"); LL.bindClass("java.util.HashMap"); LL.bindClass("java.util.ArrayList"); LL.bindClass("android.R"); LL.bindClass("java.io.FileWriter"); LL.bindClass("java.io.File"); LL.bindClass("android.os.Environment"); LL.bindClass("java.io.FileReader"); LL.bindClass("java.io.BufferedReader"); //function to display a grouped list where the user can select one item //items should be an array containing arrays which first item is the group and the second item is an array of the items in this group //onClickFunction has to have two arguments. first is group position, second is child position function expandableList(items,onClickFunction,title) { var builder=new AlertDialog.Builder(LL.getContext()); var view=new ExpandableListView(LL.getContext()); //transform array of items into the correct format var groupData=new ArrayList(); var childData=new ArrayList(); for(var x=0;x<items.length;x++) { var gd=new HashMap(); gd.put("root",items[x][0]); var cd=new ArrayList(); groupData.add(gd); for(var y=0;y<items[x][1].length;y++) { var cdMap=new HashMap(); cdMap.put("child",items[x][1][y]); cd.add(cdMap); } childData.add(cd); } //assign the items to an adapter var adapter=new SimpleExpandableListAdapter(LL.getContext(),groupData,R.layout.simple_expandable_list_item_1,["root"],[R.id.text1],childData,R.layout.simple_expandable_list_item_1,["child"],[R.id.text1]); //set function to run on Click to listener var listener=new ExpandableListView.OnChildClickListener() { onChildClick:function(parent,view,groupPosition,childPosition,id) { dialog.dismiss(); setTimeout(function(){onClickFunction(groupPosition,childPosition);},0); return true; } } //assign adapter and listener to listview view.setAdapter(adapter); view.setOnChildClickListener(listener); //finish building builder.setView(view); builder.setCancelable(true); builder.setTitle(title); builder.setNegativeButton("Cancel",new DialogInterface.OnClickListener(){onClick:function(dialog,id){dialog.cancel();}}); dialog=builder.create(); dialog.show(); } //function to display a List in a Popup, where the user can select one item function list(items,listener,title) { var builder=new AlertDialog.Builder(LL.getContext()); builder.setItems(items,listener); builder.setCancelable(true); builder.setTitle(title); builder.setNegativeButton("Cancel",new DialogInterface.OnClickListener(){onClick:function(dialog,id){dialog.cancel();}});//it has a Cancel Button builder.create().show(); } //helper function for item related, compute the center of an item function center(item) { var r=item.getRotation()*Math.PI/180; var sin=Math.abs(Math.sin(r)); var cos=Math.abs(Math.cos(r)); var w=item.getWidth()*item.getScaleX(); var h=item.getHeight()*item.getScaleY(); return[item.getPositionX()+(w*cos+h*sin)*0.5,item.getPositionY()+(h*cos+w*sin)*0.5]; } //helper function for sorting labels function noCaseSort(a,b) { if(a.toLowerCase()>b.toLowerCase())return 1; if(a.toLowerCase()<b.toLowerCase())return -1; return 0; } var hasItem=(LL.getEvent().getItem()!=null); //define Strings to display var title="What do you want to do?"; var items=[["Information",hasItem?["Event","Container","Item","Intent","Open in Market"]:["Event","Container"]],["Item Utilities",["Attach/Detach all Items","Resize all detached Items","Delete all Items","Move Pages"]],["Script Tools",["Export Scripts","Import Script","Autoformat Scripts"]],["Other",["Reset Tag","Reset Tool © by TrianguloY","Save changes"]]]; //handle user selection function onClick(groupPosition,childPosition) { switch(groupPosition) { case 0://Information switch(childPosition) { case 0://Event related var e=LL.getEvent(); try//test if event contains touch data { e.getTouchScreenX(); var ok=true; } catch(Exception) { var ok=false; } alert("Source: "+e.getSource()+"\nDate: "+e.getDate()+"\nContainer: "+e.getContainer()+"\nItem: "+e.getItem()+(ok?("\nTouch: "+e.getTouchX()+","+e.getTouchY()+"\nTouch (Screen): "+e.getTouchScreenX()+","+e.getTouchScreenY()):"")); break; case 1://container related var c=LL.getEvent().getContainer(); var t=c.getType();//Differentiate between Desktop and other containers alert("Type: "+t+"\nName/Label: "+(t=="Desktop"?c.getName():c.getOpener().getLabel())+"\nID: "+c.getId()+"\nTag: "+c.getTag()+"\nSize: "+c.getWidth()+","+c.getHeight()+"\nBoundingbox: "+c.getBoundingBox()+"\nCell Size: "+c.getCellWidth()+","+c.getCellHeight()+"\nCurrent Position: "+c.getPositionX()+","+c.getPositionY()+"\nCurrent Scale: "+c.getPositionScale()+"\nItems: "+c.getItems()); break; case 2://item related var i=LL.getEvent().getItem(); alert(i==null/*check if event contains item*/?"no item found":"Label: "+i.getLabel()+"\nType: "+i.getType()+"\nTag: "+i.getTag()+"\nID: "+i.getId()+"\nSize: "+i.getWidth()+","+i.getHeight()+"\nPosition: "+i.getPositionX()+","+i.getPositionY()+"\nScale: "+i.getScaleX()+","+i.getScaleY()+"\nAngle: "+i.getRotation()+"\nCenter: "+center(i)+((i.getType()=="Shortcut"||i.getType()=="Folder")?"\nIntent:"+i.getIntent():"")); break; case 3://intent it=LL.getEvent().getItem(); if(it==null) alert("No Intent found."); else alert("Intent: "+it.getIntent()+"\nExtras: "+it.getIntent().getExtras()); break; case 4://open the market page of this app try { LL.startActivity(Intent(Intent.ACTION_VIEW,Uri.parse("market://details?id="+LL.getEvent().getItem().getIntent().getComponent().getPackageName()))); } catch(Exception) { alert("No App found"); } break; } break; case 1://item utilities switch(childPosition) { case 0://Attach/Detach all items var items=LL.getEvent().getContainer().getItems(); var togrid=confirm("Attach? if not, detach"); for(x=0;x<items.length;x++) { var i=items.getAt(x); i.getProperties().edit().setBoolean("i.onGrid",togrid).commit(); } break; case 1://resize detached items try { var s=JSON.parse("["+prompt("which size? (input like width,height)","")+"]"); var items=LL.getEvent().getContainer().getItems(); for(var a=0;a<items.length;a++) items.getAt(a).setSize(s[0],s[1]); } catch(Exception) { Android.makeNewToast("Invalid input",true).show(); } break; case 2://delete items if(confirm("Are you sure?")) { var c=LL.getEvent().getContainer(); var i=c.getItems(); for(a=0;a<i.length;a++) c.removeItem(i.getAt(a)); } break; case 3://move pages var cont=LL.getEvent().getContainer(); var items=cont.getItems(); var cwidth=cont.getWidth(); var cheight=cont.getHeight(); var cellsFloatX=cwidth/cont.getCellWidth(); var cellsFloatY=cheight/cont.getCellHeight(); var cellsX=Math.round(cellsFloatX); var cellsY=Math.round(cellsFloatY); //check for safe cell sizes if(Math.abs(cellsFloatX-cellsX)>0.00001) if(!confirm("Warning, the cells don't fill the screen as an exact horizontal number.\nDo you want to continue?"))return; if(Math.abs(cellsFloatY-cellsY)>0.00001) if(!confirm("Warning, the cells don't fill the screen as an exact vertical number.\nDo you want to continue?"))return; try { //page(s) selection var s=prompt("Which page do you want to move? (* for all) input has to be x,y (e.g. *,* for all pages)","").split(","); var move=JSON.parse("[\""+s[0]+"\",\""+s[1]+"\"]"); var done=true; } catch(Exception) { var done=false; } //check for valid input if(!done||move==null||move[0]==null||(move[0]!="*"&&isNaN(parseInt(move[0])))||move[1]==null||(move[1]!="*"&&isNaN(parseInt(move[1])))) { Android.makeNewToast("Invalid input",true).show(); return; } //format to int if needed if(move[0]!="*")move[0]=parseInt(move[0]); if(move[1]!="*")move[1]=parseInt(move[1]); try { //user selection: destination var dist=JSON.parse("["+prompt("How far do you want to move? input has to be x,y (e.g. 1,0 for one page right)","")+"]"); var done=true; } catch(Exception) { var done=false; } //check for valid input if(!done||dist==null||dist[0]==null||isNaN(dist[0])||dist[1]==null||isNaN(dist[1])) { Android.makeNewToast("Invalid input",true).show(); return; } if(dist[0]==0&&dist[1]==0)return;//if nothing to do, do nothing :P //do the movement for(var i=items.getLength()-1;i>=0;--i) { var item=items.getAt(i); var pos=[item.getPositionX(),item.getPositionY()]; //check if item should be moved if((move[0]=="*"||(pos[0]>=cwidth*move[0]&&pos[0]<cwidth*(move[0]+1)))&&(move[1]=="*"||(pos[1]>=cheight*move[1]&&pos[1]<cheight*(move[1]+1)))) { var prop=item.getProperties(); //handle pinned item var xx=1,yy=1; var pinmode=prop.getString("i.pinMode"); if(pinmode[0]=="X")xx=0; if(pinmode.indexOf("Y")!=-1)yy=0; //move it if(prop.getBoolean("i.onGrid")) { var cell=item.getCell(); item.setCell(cell.getLeft()+cellsX*dist[0]*xx,cell.getTop()+cellsY*dist[1]*yy,cell.getRight()+cellsX*dist[0]*xx,cell.getBottom()+cellsY*dist[1]*yy); } else {item.setPosition(pos[0]+cwidth*dist[0]*xx,pos[1]+cheight*dist[1]*yy); } } } LL.save(); break; } break; case 2://Script Tools switch(childPosition) { case 0://export //Directory to save scripts in var dir=new File(Environment.getExternalStorageDirectory()+File.separator+"LightningLauncher"+File.separator+"Scripts"+File.separator); dir.mkdirs();//create Directory if missing //Iterate through all scripts var scripts=LL.getAllScriptMatching(Script.FLAG_ALL); for(var a=0;a<scripts.length;a++) { var s=scripts.getAt(a); var file=new File(Environment.getExternalStorageDirectory()+File.separator+"LightningLauncher"+File.separator+"Scripts"+File.separator+s.getName()+".txt");//Define the file to save in file.createNewFile();//create the file //Check for Flags var app=s.hasFlag(Script.FLAG_APP_MENU); var item=s.hasFlag(Script.FLAG_ITEM_MENU); var custom=s.hasFlag(Script.FLAG_CUSTOM_MENU); var flags=""; if(app||item||custom) { flags="//Flags" if(app)flags+=" app"; if(item)flags+=" item"; if(custom)flags+=" custom"; flags+="\n"; } //write the code to the file var f=new FileWriter(file); f.write(flags+s.getText()); f.flush(); f.close(); } Android.makeNewToast("Scripts saved to "+dir.getAbsolutePath(),true).show(); break; case 1://import //ask android to let the user select a textfile var i=new Intent(Intent.ACTION_GET_CONTENT); i.setType("text/*"); i.addCategory(Intent.CATEGORY_OPENABLE); LL.startActivityForResult(Intent.createChooser(i,"Select Script to import"),LL.getCurrentScript(),null); break; case 2://autoformat //config var directWrite=true;//wether to show a prompt or write directly to the script //endconfig //create Strings to display var title="Which script?"; var items=[]; var scripts=LL.getAllScriptMatching(Script.FLAG_ALL); for(var z=0;z<scripts.length;z++)items.push(scripts.getAt(z).getName()); items.sort(noCaseSort); items.unshift("All Scripts (may need some time)"); //initialize vars var switchLevel; var i; var s; var t; var out; var noCode; var starter; var newLine; //handle user selection var listener=new DialogInterface.OnClickListener(){ onClick:function(dialog,id) { var selected; if(id==0)selected=items.slice(1,items.length);//all scripts selected else selected=[items[id]];//single script selected for(var y=0;y<selected.length;y++) { s=LL.getScriptByName(selected[y]); t=s.getText();//original text out="";//output i=0;//indentionlevel noCode=false;//detectionhelper,true if in comment,string etc. starter;//detectionhelper,contains the last noCode block starter newLine=true;//true if in a new line switchLevel=[];//detectionhelper,needed for switch commands //go through the text for(a=0;a<t.length;a++) { //don't copy spaces and tabs, if not in a noCode block if(!noCode&&((t[a]==" "&&(out[out.length-1].toLowerCase()==out[out.length-1].toUpperCase()||t[a+1].toLowerCase()==t[a+1].toUpperCase())&&out.slice(out.length-4,out.length)!="case"&&out.slice(out.length-6,out.length)!="return")||(t[a]=="\t")))continue; //detect wether the char is negated by a backslash or not var backslashed=false; for(b=out.length-1;out[b]=="\\";b--)backslashed=!backslashed; //detect start of a noCode block if((t[a]=="\""||t[a]=="\'")&&!noCode) { noCode=true; starter=t[a]; if(out[out.length-1]=="\n")indentLine(); } else if(!noCode&&t[a]=="/"&&(t[a+1]=="/"||t[a+1]=="*")) { noCode=true; starter=t.slice(a,a+2); if(out[out.length-1]=="\n")indentLine(); } //detect end of a noCode block else if(noCode&&(t[a]==starter||(starter=="/*"&&t.slice(a,a+2)=="*/")||(starter=="//"&&t[a]=="\n"))&&!backslashed) { noCode=false; } //handle keychars if(!noCode) { if(t[a]=="\n")//line end { newLine=true; out=out.concat(t[a]); continue; } if(t[a]=="}")//function block end { i--; if(switchLevel.length!=0&&i<=switchLevel[0]&&switchLevel[0]>0)//special handling when in switch command { switchLevel.shift(); i--; } } if(newLine&&t[a]!="\n")//indent the next line { indentLine(); } if(t[a]=="{")i++;//function block start if(t.slice(a,a+7)=="switch(")switchLevel.unshift(++i);//start of switch command } out=out.concat(t[a]);//concat the char } while(out[out.length-1]=="\n")out=out.slice(0,out.length-1);//remove unnessecary line brakes at the end of the script if(directWrite)//set output to the script { s.setText(out); if(y==selected.length-1)Android.makeNewToast("Done!",true).show();//notify if finished } else prompt("",out);//show output } } } //show selection list list(items,listener,title); //creates tabs at the beginning of a line function indentLine() { for(b=(switchLevel!=0&&(t.slice(a,a+4)=="case"||t.slice(a,a+7)=="default")?1:0);b<i;b++) out=out.concat("\t"); newLine=false; } break; } break; case 3://other switch(childPosition) { case 0://reset Tag var d=LL.getEvent().getContainer(); var i=LL.getEvent().getItem();(i!=null?i:d).setTag(null); Android.makeNewToast((i==null?"container":"item")+"s tag resetted.",false).show(); break; case 1://reset tool by trianguloY, ask him how it works :D var cont=LL.getEvent().getContainer(); var items=cont.getItems(); var bools=[];bools[0]=confirm("Reset cell? (only grid items) [0,0]"); bools[1]=confirm("Reset position? (only free items) [0,0] "); bools[2]=confirm("Reset rotation? (only free items) [0]"); bools[3]=confirm("Reset scale? (only free items) [1,1]"); bools[4]=confirm("Reset skew? (only free items) [0,0]"); bools[5]=confirm("Reset size? (only free items) [cell size]"); bools[6]=confirm("Reset visibility? [true]"); for(var i=0;i<items.getLength();++i) { var t=items.getAt(i); if(bools[0])t.setCell(0,0,1,1); if(bools[1])t.setPosition(0,0); if(bools[2])t.setRotation(0); if(bools[3])t.setScale(1,1); if(bools[4])t.setSkew(0,0); if(bools[5])t.setSize(cont.getCellWidth(),cont.getCellHeight()); if(bools[6])t.setVisibility(true); } break; case 2: LL.save(); Android.makeNewToast("Done!",true).show(); break; } break; default://should never occur: illegal group selection Android.makeNewToast(txt==null?"Aborted":"illegal case: "+txt,false).show(); break; } } if(typeof resultCode==='undefined')//normal run { //display the list expandableList(items,onClick,title); } else//user has selected a file to import { //the file to import var file=new File(data.getData().getPath()); //check for valid file if(!file.canRead()) { alert("Can't read file"); return; } if(file.length()>25000) { alert("File is too big"); return; } var r=new BufferedReader(new FileReader(file)); var s=""; //read the file var l=r.readLine(); if(l.indexOf("//Flags")!=-1)//check if file contains flag settings { var app=(l.indexOf("app")!=-1); var item=(l.indexOf("item")!=-1); var custom=(l.indexOf("custom")!=-1); } else s=l+"\n"; while((l=r.readLine())!=null)s+=(l+"\n"); //remove file extension var filename=file.getName(); var index=filename.lastIndexOf("."); if(index!=-1)filename=filename.slice(0,index); //ask for imported scripts name var name=prompt("File read successfully. Enter name for the Script",filename); //Write read data to script and create it if nessecary var script=LL.getScriptByName(name); if(script!=null) { if(!confirm("Script does already exist. Overwrite?"))return; else script.setText(s); } else script=LL.createScript(name,s,0); //aplly flags if found before if(app)script.setFlag(Script.FLAG_APP_MENU,true); if(item)script.setFlag(Script.FLAG_ITEM_MENU,true); if(custom)script.setFlag(Script.FLAG_CUSTOM_MENU,true); Android.makeNewToast("Done!",true); } </sxh>