/* * Software Name : ATK * * Copyright (C) 2007 - 2012 France Télécom * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ------------------------------------------------------------------ * File Name : ScriptJPanel.java * * Created : 26/10/2009 * Author(s) : France Telecom */ package com.orange.atk.scriptRecorder.scriptJpanel; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Vector; import javax.swing.DefaultCellEditor; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeCellEditor; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import org.apache.log4j.Logger; import com.orange.atk.interpreter.ast.ASTFUNCTION; import com.orange.atk.interpreter.ast.ASTNUMBER; import com.orange.atk.interpreter.ast.ASTSTRING; import com.orange.atk.interpreter.ast.ASTStart; import com.orange.atk.interpreter.parser.ATKScriptParserTreeConstants; import com.orange.atk.scriptRecorder.RecorderFrame; import com.orange.atk.scriptRecorder.ScriptController; public class ScriptJPanel extends JScrollPane { private static final long serialVersionUID = -4677424545754191554L; private DefaultMutableTreeNode root; private DefaultTreeModel treemodel; private ScriptTreeRenderer renderer; private Boolean isempty=true; private JPopupMenu rightPopup; private RecorderFrame recframe; protected JTree tree; /** * Default constructor */ public ScriptJPanel(RecorderFrame rf) { super(); recframe = rf; root = new DefaultMutableTreeNode("root", true); treemodel = new DefaultTreeModel(root); tree = new JTree(treemodel); tree.setEditable(true); tree.getSelectionModel().setSelectionMode(TreeSelectionModel.CONTIGUOUS_TREE_SELECTION); tree.setShowsRootHandles(true); tree.setRootVisible(false); tree.putClientProperty("JTree.lineStyle", "None"); //remove icons on Jtree renderer = new ScriptTreeRenderer(); renderer.setOpenIcon(null); renderer.setClosedIcon(null); renderer.setLeafIcon(null); tree.setCellRenderer(renderer); //add the tree setPreferredSize(new Dimension(150,400)); setAutoscrolls(true); setViewportView(tree); //detect when editing is finished TreeCellEditor tce = new DefaultCellEditor(new AutoCompleteJtextField(tree)); tree.setCellEditor(tce); tree.addMouseListener(new MouseListener(){ public void mouseClicked(MouseEvent arg0) { if (arg0.getButton()==MouseEvent.BUTTON3){ //RightClick if(tree.getSelectionCount()<=1) tree.setSelectionPath(tree.getPathForLocation( arg0.getX(), arg0.getY() )); if (isSelectionInsideInclude()) JOptionPane.showMessageDialog(null, "Include script lines can not be modified !"); else { if (rightPopup ==null) newRightPopup(); rightPopup.setLocation(arg0.getXOnScreen(), arg0.getYOnScreen() ); rightPopup.setVisible(true); } } if (arg0.getButton()==MouseEvent.BUTTON1&& rightPopup!=null) rightPopup.setVisible(false); } public void mouseEntered(MouseEvent arg0) {} public void mouseExited(MouseEvent arg0) {} public void mousePressed(MouseEvent arg0) {} public void mouseReleased(MouseEvent arg0) {} }); } private boolean isSelectionInsideInclude() { boolean isSelectionInsideInclude = true; for(int i=0; i<tree.getSelectionCount() && isSelectionInsideInclude ; i++) { int pathLength = tree.getSelectionPaths()[i].getPathCount(); boolean includeFound=false; int j; for (j=0; j<pathLength && !includeFound; j++) { if (tree.getSelectionPaths()[i].getPathComponent(j).toString().startsWith("Include")) includeFound=true; } if (!includeFound || j==pathLength) isSelectionInsideInclude=false; } return isSelectionInsideInclude; } private boolean isInsideInclude(MutableTreeNode node) { if (node == null) return false; if ((node.toString()).indexOf("Include")!=-1) return true; else return isInsideInclude((MutableTreeNode) node.getParent()); } /** * Method to call when the AST has been modified. * Rebuild UI with ast manipulation classes. * @return */ public synchronized boolean update() { // Logger.getLogger(this.getClass() ).debug("update de l'ast est appellé"); ASTStart ast = ScriptController.getScriptController().getAST(); //build depanding the visitor ASTtoJTreeVisitor visitor = new ASTtoJTreeVisitor(); root.removeAllChildren(); //build the tree if (ast !=null) { List<DefaultMutableTreeNode> scripttree = (List<DefaultMutableTreeNode>) ast.jjtAccept(visitor,null); for(DefaultMutableTreeNode el : scripttree) root.add(el); } isempty = root.isLeaf(); // Logger.getLogger(this.getClass() ).debug("estimation de l'arbre graphique :"+root.getLeafCount()); treemodel.reload(); expandTree(); return false; } /**Convert TreePath in List * * @param tp a Tree Path * @return List<Integer> which correspond to indexes of child Node on the way */ protected List<Integer> toList(TreePath tp) { //find the position of JTextfield in the tree List<Integer> Path = new ArrayList<Integer>(); TreeNode parentnode = (TreeNode) tp.getPathComponent(0); for (int i=1 ; i<tp.getPathCount() ; i++) { TreeNode childnode = (TreeNode) tp.getPathComponent(i); //TODO : improve. //Hack for loop car parent.getIndex(0) correspond to number of loop in AST int offset=0; if ( ((DefaultMutableTreeNode) parentnode).toString().startsWith("Loop") ) offset =1; Path.add(parentnode.getIndex(childnode)+offset); parentnode = childnode; } return Path; } protected void newRightPopup() { Logger.getLogger(this.getClass() ).debug("create right popup"); rightPopup = new JPopupMenu(); JMenuItem jmiDelete =new JMenuItem("Delete Selected Lines"); jmiDelete.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { TreePath[] tps = tree.getSelectionPaths(); if (tps !=null) { Vector<List<Integer>> treepathsIndex = new Vector<List<Integer>> (); for( int i =0 ; i<tps.length ; i++) treepathsIndex.add( toList(tps[i]) ); ScriptController.getScriptController().delete( treepathsIndex); recframe.updateScript(); } rightPopup.setVisible(false); } }); rightPopup.add(jmiDelete); //TODO: active these codes lines /* JMenuItem jmiRun= new JMenuItem("Run Selected Lines"); jmiRun.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { rightPopup.setVisible(false); // runScript(); } }); rightPopup.add(jmiRun); */ JMenuItem jmiSurround=new JMenuItem("Surround with Loop"); jmiSurround.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { TreePath[] tps = tree.getSelectionPaths(); if (tps !=null) { Vector<List<Integer>> treepathsIndex = new Vector<List<Integer>> (); for( int i =0 ; i<tps.length ; i++) treepathsIndex.add( toList(tps[i]) ); String nbLoop = JOptionPane.showInputDialog("Number of Loop :"); ScriptController.getScriptController().surroundLoop(treepathsIndex ,nbLoop); recframe.updateScript(); } rightPopup.setVisible(false); } }); rightPopup.add(jmiSurround); JMenuItem jmiComment=new JMenuItem("Comment/Uncomment lines"); jmiComment.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { TreePath[] tps = tree.getSelectionPaths(); if (tps !=null) { for( TreePath tp : tps ) ScriptController.getScriptController().comment(toList(tp) ); recframe.updateScript(); } rightPopup.setVisible(false); } }); rightPopup.add(jmiComment); JMenuItem jmiInsertb=new JMenuItem("Insert line Before "); jmiInsertb.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { // chooseAction("Insert"); //after the node selected TreePath selected = tree.getSelectionPaths()[0]; MutableTreeNode newnode = new DefaultMutableTreeNode(" new "); if(selected!=null) { MutableTreeNode selectednode = (MutableTreeNode) selected.getLastPathComponent(); MutableTreeNode parent = (MutableTreeNode) selectednode.getParent(); if (!isInsideInclude(parent)) { treemodel.insertNodeInto( newnode, parent, parent.getIndex(selectednode)); tree.startEditingAtPath(selected.getParentPath() .pathByAddingChild(newnode)); rightPopup.setVisible(false); } else { rightPopup.setVisible(false); JOptionPane.showMessageDialog(null, "Can not insert line inside Include script"); } //The Tree is empty } else { root.add(newnode); treemodel.reload(); Object[] path = { root , newnode}; tree.startEditingAtPath(new TreePath(path) ); rightPopup.setVisible(false); } } }); rightPopup.add(jmiInsertb); JMenuItem jmiInsert=new JMenuItem("Insert line after "); jmiInsert.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { // chooseAction("Insert"); //after the node selected TreePath selected = tree.getSelectionPaths()[tree.getSelectionCount()-1]; MutableTreeNode newnode = new DefaultMutableTreeNode(" new "); if(selected!=null) { MutableTreeNode selectednode = (MutableTreeNode) selected.getLastPathComponent(); MutableTreeNode parent = (MutableTreeNode) selectednode.getParent(); if (!isInsideInclude(parent)) { treemodel.insertNodeInto( newnode, parent, parent.getIndex(selectednode)+1); tree.startEditingAtPath(selected.getParentPath() .pathByAddingChild(newnode)); rightPopup.setVisible(false); } else { rightPopup.setVisible(false); JOptionPane.showMessageDialog(null, "Can not insert line inside Include script"); } //The Tree is empty } else { root.add(newnode); treemodel.reload(); Object[] path = { root , newnode}; tree.startEditingAtPath(new TreePath(path) ); rightPopup.setVisible(false); } } }); rightPopup.add(jmiInsert); /* JMenuItem jmiModify=new JMenuItem("Modify this line"); jmiInsert.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { // chooseAction("Modify"); rightPopup.setVisible(false); } }); rightPopup.add(jmiModify);*/ /* if(ScriptController.getScriptController().isRecording()) jmiRun.setEnabled(false);*/ JMenuItem jmiStartIntstrumetation=new JMenuItem("Start instrumentation"); jmiStartIntstrumetation.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { Thread progress = new Thread(){ @Override public void run() { recframe.glassPane.setText("Getting all installed APK"); recframe.glassPane.start(); Thread progress1 = new Thread() { @Override public void run() { // recframe.getViewsFunction(); recframe.selectAPK(); if(!RecorderFrame.PackageName.equalsIgnoreCase("")&& !RecorderFrame.MainActivityName.equalsIgnoreCase("")&& !RecorderFrame.PackageSourceDir.equalsIgnoreCase("")) { int index = tree.getSelectionRows()[tree.getSelectionCount()-1]; ASTStart ast = ScriptController.getScriptController().getAST(); ASTFUNCTION startTest = new ASTFUNCTION(ATKScriptParserTreeConstants.JJTFUNCTION); startTest.setValue("StartRobotiumTestOn"); ASTSTRING param1 = new ASTSTRING(ATKScriptParserTreeConstants.JJTSTRING); param1.setValue("'"+RecorderFrame.PackageName+"'"); ASTSTRING param2 = new ASTSTRING(ATKScriptParserTreeConstants.JJTSTRING); param2.setValue("'"+RecorderFrame.MainActivityName+"'"); ASTSTRING param3 = new ASTSTRING(ATKScriptParserTreeConstants.JJTSTRING); param3.setValue("'"+RecorderFrame.PackageSourceDir+"'"); ASTNUMBER param4 = new ASTNUMBER(ATKScriptParserTreeConstants.JJTNUMBER); param4.setValue(String.valueOf(RecorderFrame.Versioncode)); startTest.jjtAddChild(param1, 0); startTest.jjtAddChild(param2, 1); startTest.jjtAddChild(param3, 2); startTest.jjtAddChild(param4, 3); ASTFUNCTION exitSolo = new ASTFUNCTION(ATKScriptParserTreeConstants.JJTFUNCTION); exitSolo.setValue("ExitSolo"); int numberOfchild =ast.jjtGetNumChildren(); for(int i =numberOfchild+1; i>index+2; i-- ) { ast.jjtAddChild(ast.jjtGetChild(i-2),i); } ast.jjtAddChild(startTest,index+1); ast.jjtAddChild(exitSolo,index+2); update(); } } }; progress1.start(); } }; progress.start(); rightPopup.setVisible(false); } }); rightPopup.add(jmiStartIntstrumetation); } /** * Return true if the Jtree is Empty * that's means there are no code * @return */ //TODO : move this kind of verification in controller public Boolean isEmpty() { return isempty; } public synchronized void setRunningNode(int nodeLineNumber) { TreeNode node = null; nodeLineNumber--; expandTree(); if (nodeLineNumber>=0 && nodeLineNumber<tree.getRowCount()) { node = (TreeNode) tree.getPathForRow(nodeLineNumber).getLastPathComponent(); } renderer.setRunningNode(node); treemodel.reload(); expandTree(); // TODO faire marcher le scroll automatique //if (node !=null) tree.scrollRectToVisible(tree.getRowBounds(nodeLineNumber)); } private void expandTree() { for(int i=0;i<tree.getRowCount();i++) tree.expandRow(i); } public int getSelectedNode(){ TreePath[] tps = tree.getSelectionPaths(); if (tps !=null){ TreePath selected = tree.getSelectionPaths()[tree.getSelectionCount()-1]; if(selected!=null){ MutableTreeNode selectednode = (MutableTreeNode) selected.getLastPathComponent(); MutableTreeNode parent = (MutableTreeNode) selectednode.getParent(); return parent.getIndex(selectednode); } } return -1; } public String searchNode(String nodeStr) { DefaultMutableTreeNode node = null; Enumeration e = root.breadthFirstEnumeration(); while (e.hasMoreElements()) { node = (DefaultMutableTreeNode) e.nextElement(); if ((node.getUserObject().toString()).contains(nodeStr)) { return node.getUserObject().toString(); } } return null; } }