public class MletHtmlCanvas implements ICanvas, IMletCanvas, HCJSInterface { private static final String NO_COMPONENT_HCCODE = "no component hccode : "; final int width, height; public HTMLMlet mlet; public ProjectContext projectContext; static final boolean isAndroidServer = ResourceUtil.isAndroidServerPlatform(); public JFrame frame; JScrollPane scrollPane; private byte[] screenIDbs; private char[] screenIDChars; private String screenID, title; private DifferTodo differTodo; private final boolean isSimu; final J2SESession coreSS; boolean isForDialog; public MletHtmlCanvas(final J2SESession coreSS, final int w, final int h) { isSimu = PropertiesManager.isSimu(); this.coreSS = coreSS; this.width = w; this.height = h; } private final void printComp(final Component comp, final int deep) { final Rectangle rect = comp.getBounds(); if (L.isInWorkshop) { System.out.println( comp.getClass().getName() + deep + ", x : " + rect.x + ", y : " + rect.y + ", w : " + rect.width + ", h : " + rect.height); } if (comp instanceof Container) { final Container container = (Container) comp; final int count = container.getComponentCount(); for (int i = 0; i < count; i++) { printComp(container.getComponent(i), deep + 1); } } else if (comp instanceof JScrollPane) { if (L.isInWorkshop) { System.out.println("------This is JScrollPane-----"); } printComp(((JScrollPane) comp).getViewport().getView(), deep); } } @Override public final void onStart() { // differTodo.executeJS(hcj2seScript); // differTodo.loadJS("msg = \"hello' abc \\'world\";"); // 必须置于上两段初始代码传送之后 final boolean rtl = LangUtil.isRTL(UserThreadResourceUtil.getMobileLocaleFrom(coreSS)); if (rtl) { differTodo.setLTR(!rtl); } final ProjResponser projResponser = ServerUIAPIAgent.getProjResponserMaybeNull(projectContext); if (projResponser != null) { // AddHar下可能为null final String dftStyles = (String) projResponser.map.get(HCjar.PROJ_STYLES); final String defaultStyles = (dftStyles == null ? "" : dftStyles.trim()); // AddHAR可能出现null if (defaultStyles.length() > 0) { final String replaceVariable = StyleManager.replaceVariable(coreSS, defaultStyles, mlet, projectContext); // L.V = L.O ? false : LogManager.log(replaceVariable); differTodo.loadStyles(replaceVariable); } } ServerUIAPIAgent.setDiffTodo(mlet, differTodo); // printComp(scrolPanel, 0); // 必须置于notifyInitDone之前,因为有可能增加Mlet级样式和用户setStylesJComponentXX ScreenServer.onStartForMlet(coreSS, projectContext, mlet); } @Override public final void onPause() { ScreenServer.onPauseForMlet(coreSS, projectContext, mlet); } @Override public final void onResume() { ScreenServer.onResumeForMlet(coreSS, projectContext, mlet); } @Override public final void onExit() { onExit(false); } boolean isExitProcced; @Override public void onExit(final boolean isAutoReleaseAfterGo) { synchronized (this) { if (isExitProcced) { return; } else { isExitProcced = true; } } if (L.isInWorkshop) { L.V = L.O ? false : LogManager.log("onExit MletHtmlCanvas : " + mlet.getTarget()); } ScreenServer.onExitForMlet(coreSS, projectContext, mlet, isAutoReleaseAfterGo); MultiUsingManager.exit( coreSS, ServerUIAPIAgent.buildScreenID(projectContext.getProjectID(), mlet.getTarget())); frame.dispose(); } @Override public final void setMlet( final J2SESession coreSS, final Mlet mlet, final ProjectContext projectCtx) { if (mlet instanceof DialogHTMLMlet) { isForDialog = true; ((DialogHTMLMlet) mlet).resLock.mletCanvas = this; } this.mlet = (HTMLMlet) mlet; ServerUIAPIAgent.setProjectContext(mlet, projectCtx); projectContext = projectCtx; frame = new JFrame(); // 不能入Session会导致block showWindowWithoutWarningBanner ServerUIAPIAgent.runAndWaitInSessionThreadPool( coreSS, ServerUIAPIAgent.getProjResponserMaybeNull(projectContext), new ReturnableRunnable() { @Override public Object run() { scrollPane = new JScrollPane( mlet, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); return null; } }); differTodo = new DifferTodo(coreSS, screenID, mlet); } /** * in Android server, AddHarHTMLMlet is NOT need to adapter size. * * @param scrollPane * @return */ public static boolean isForAddHtml(final JScrollPane scrollPane) { if (scrollPane != null) { final JViewport jviewport = scrollPane.getViewport(); if (jviewport != null) { final Component view = jviewport.getView(); if (view != null && view instanceof SystemHTMLMlet) { return true; } } } return false; } @Override public final void init() { // in user thread // 注意:mlet外加JScrollPane时,在Window XP, JRE 7会出现height不能大于1024的情形,Mac无此问题,故关闭JScrollPane // 因为如下会发生,所以加4 // javax.swing.JScrollPane0, x : 0, y : 0, w : 100, h : 100 // javax.swing.JViewport1, x : 2, y : 2, w : 96, h : 96 frame.setContentPane(scrollPane); if (isAndroidServer) { scrollPane.setPreferredSize(new Dimension(width, height)); } else { mlet.setPreferredSize(new Dimension(width, height)); } frame.pack(); // 可能重载某些方法 } @Override public final void setScreenIDAndTitle(final String screenID, final String title) { this.screenID = screenID; this.screenIDbs = ByteUtil.getBytes(screenID, IConstant.UTF_8); this.screenIDChars = screenID.toCharArray(); this.title = title; } @Override public boolean isSameScreenID(final byte[] bs, final int offset, final int len) { return ByteUtil.isSame(screenIDbs, 0, screenIDbs.length, bs, offset, len); } @Override public boolean isSameScreenIDIgnoreCase(final char[] chars, final int offset, final int len) { if (len == screenIDChars.length) { for (int i = 0, j = offset; i < len; ) { final char c1 = screenIDChars[i++]; final char c2 = chars[j++]; if (c1 == c2 || Character.toUpperCase(c1) == Character.toUpperCase(c2) || Character.toLowerCase(c1) == Character.toLowerCase(c2)) { } else { return false; } } return true; } else { return false; } } private final boolean matchCmd(final byte[] cmdbs, final byte[] bs, final int offset) { final int len = cmdbs.length; for (int i = 0; i < len; i++) { if (cmdbs[i] != bs[offset + i]) { return false; } } return true; } private final int searchNextSplitIndex(final byte[] bs, final int startIdx) { final int endIdx = bs.length; for (int i = startIdx; i < endIdx; i++) { if (bs[i] == JSCore.splitBS[0]) { final int endSplitBS = JSCore.splitBS.length; if (i + JSCore.splitBS.length < endIdx) { boolean isDiff = false; for (int j = 1; j < endSplitBS; j++) { if (bs[i + j] != JSCore.splitBS[j]) { isDiff = true; break; } } if (isDiff == false) { return i; } } } } return -1; } @Override public final void actionJSInput(final byte[] bs, final int offset, final int len) { if (isForDialog) { final DialogHTMLMlet dialog = (DialogHTMLMlet) mlet; if (dialog.isContinueProcess() == false) { return; } } ServerUIAPIAgent.runAndWaitInSessionThreadPool( coreSS, ServerUIAPIAgent.getProjResponserMaybeNull(projectContext), new ReturnableRunnable() { // 事件的先后性保证 @Override public Object run() { actionJSInputInUser(bs, offset, len); return null; } }); } private final void actionJSInputInUser(final byte[] bs, final int offset, final int len) { if (isSimu) { try { L.V = L.O ? false : LogManager.log( "action JS input : " + new String(bs, offset, len, IConstant.UTF_8)); } catch (final Throwable e1) { e1.printStackTrace(); } } // ------------------------------------------------------- // 重要 // 如果以下增加事件接收,请同步CodeItem.AnonymousClass // ------------------------------------------------------- try { if (matchCmd(JSCore.actionExt, bs, offset)) { final String cmd = getOneValue(JSCore.actionExt, bs, offset, len); actionExt(cmd); return; } else if (matchCmd(JSCore.clickJButton, bs, offset)) { final String id = getOneValue(JSCore.clickJButton, bs, offset, len); clickJButton(Integer.parseInt(id)); return; } else if (matchCmd(JSCore.selectComboBox, bs, offset)) { final String[] values = getTwoValue(JSCore.selectComboBox, bs, offset, len); selectComboBox(Integer.parseInt(values[0]), Integer.parseInt(values[1])); return; } else if (matchCmd(JSCore.selectSlider, bs, offset)) { final String[] values = getTwoValue(JSCore.selectSlider, bs, offset, len); selectSlider(Integer.parseInt(values[0]), Integer.parseInt(values[1])); return; } else if (matchCmd(JSCore.notifyTextFieldValue, bs, offset)) { final String[] values = getTwoValue(JSCore.notifyTextFieldValue, bs, offset, len); notifyTextFieldValue(Integer.parseInt(values[0]), values[1]); return; } else if (matchCmd(JSCore.notifyTextAreaValue, bs, offset)) { final String[] values = getTwoValue(JSCore.notifyTextAreaValue, bs, offset, len); notifyTextAreaValue(Integer.parseInt(values[0]), values[1]); return; } else if (matchCmd(JSCore.clickJRadioButton, bs, offset)) { final String id = getOneValue(JSCore.clickJRadioButton, bs, offset, len); clickJRadioButton(Integer.parseInt(id)); return; } else if (matchCmd(JSCore.clickJCheckbox, bs, offset)) { final String id = getOneValue(JSCore.clickJCheckbox, bs, offset, len); clickJCheckbox(Integer.parseInt(id)); return; } else if (matchCmd(JSCore.mouseReleased, bs, offset)) { final String[] values = getThreeValue(JSCore.mouseReleased, bs, offset, len); notifyMouseReleased( Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2])); return; } else if (matchCmd(JSCore.mousePressed, bs, offset)) { final String[] values = getThreeValue(JSCore.mousePressed, bs, offset, len); notifyMousePressed( Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2])); return; } else if (matchCmd(JSCore.mouseExited, bs, offset)) { final String[] values = getThreeValue(JSCore.mouseExited, bs, offset, len); notifyMouseExited( Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2])); return; } else if (matchCmd(JSCore.mouseEntered, bs, offset)) { final String[] values = getThreeValue(JSCore.mouseEntered, bs, offset, len); notifyMouseEntered( Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2])); return; } else if (matchCmd(JSCore.mouseClicked, bs, offset)) { final String[] values = getThreeValue(JSCore.mouseClicked, bs, offset, len); notifyMouseClicked( Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2])); return; } else if (matchCmd(JSCore.mouseDragged, bs, offset)) { final String[] values = getThreeValue(JSCore.mouseDragged, bs, offset, len); notifyMouseDragged( Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2])); return; } } catch (final Exception e) { ExceptionReporter.printStackTrace(e); } try { final String cmds = new String(bs, offset, len, IConstant.UTF_8); final String[] splits = StringUtil.splitToArray(cmds, StringUtil.SPLIT_LEVEL_2_JING); LogManager.err("unknow JS input event : " + splits[0] + ", cmd : " + cmds); } catch (final Exception e) { ExceptionReporter.printStackTrace(e); } } private final void notifyMouseReleased(final int id, final int x, final int y) { final Component comp = searchComponentByHcCode(mlet, id); if (comp != null) { final MouseListener[] mlistener = comp.getMouseListeners(); MouseEvent event = null; for (int i = 0; i < mlistener.length; i++) { if (event == null) { event = buildMouseEvent(comp, MouseEvent.MOUSE_RELEASED, x, y); } mlistener[i].mouseReleased(event); } } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } private final MouseEvent buildMouseEvent( final Component comp, final int eventID, final int x, final int y) { return new MouseEvent( comp, eventID, System.currentTimeMillis(), MouseEvent.BUTTON1_MASK, x, y, 1, false) { @Override public final Point getLocationOnScreen() { return super.getLocationOnScreen(); // TODO } @Override public final int getXOnScreen() { return super.getXOnScreen(); // TODO } @Override public final int getYOnScreen() { return super.getYOnScreen(); // TODO } }; } private final void notifyMousePressed(final int id, final int x, final int y) { final Component comp = searchComponentByHcCode(mlet, id); if (comp != null) { final MouseListener[] mlistener = comp.getMouseListeners(); MouseEvent event = null; for (int i = 0; i < mlistener.length; i++) { if (event == null) { event = buildMouseEvent(comp, MouseEvent.MOUSE_PRESSED, x, y); } mlistener[i].mousePressed(event); } } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } private final void notifyMouseExited(final int id, final int x, final int y) { final Component comp = searchComponentByHcCode(mlet, id); if (comp != null) { final MouseListener[] mlistener = comp.getMouseListeners(); MouseEvent event = null; for (int i = 0; i < mlistener.length; i++) { if (event == null) { event = buildMouseEvent(comp, MouseEvent.MOUSE_EXITED, x, y); } mlistener[i].mouseExited(event); } } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } private final void notifyMouseEntered(final int id, final int x, final int y) { final Component comp = searchComponentByHcCode(mlet, id); if (comp != null) { final MouseListener[] mlistener = comp.getMouseListeners(); MouseEvent event = null; for (int i = 0; i < mlistener.length; i++) { if (event == null) { event = buildMouseEvent(comp, MouseEvent.MOUSE_ENTERED, x, y); } mlistener[i].mouseEntered(event); } } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } private final void notifyMouseClicked(final int id, final int x, final int y) { final Component comp = searchComponentByHcCode(mlet, id); if (comp != null) { final MouseListener[] mlistener = comp.getMouseListeners(); MouseEvent event = null; for (int i = 0; i < mlistener.length; i++) { if (event == null) { event = buildMouseEvent(comp, MouseEvent.MOUSE_CLICKED, x, y); } mlistener[i].mouseClicked(event); } } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } private final void notifyMouseDragged(final int id, final int x, final int y) { final Component comp = searchComponentByHcCode(mlet, id); if (comp != null) { final MouseMotionListener[] mlistener = comp.getMouseMotionListeners(); MouseEvent event = null; for (int i = 0; i < mlistener.length; i++) { if (event == null) { event = buildMouseEvent(comp, MouseEvent.MOUSE_DRAGGED, x, y); } mlistener[i].mouseDragged(event); } } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } private final Component searchComponentByHcCode( final JPanel jpanel, final int hcCode) { // in user thread if (differTodo.buildHcCode(jpanel) == hcCode) { return jpanel; } final int compCount = jpanel.getComponentCount(); for (int i = 0; i < compCount; i++) { final Component comp = jpanel.getComponent(i); if (comp instanceof JPanel) { final Component result = searchComponentByHcCode((JPanel) comp, hcCode); if (result != null) { return result; } } else { if (differTodo.buildHcCode(comp) == hcCode) { return comp; } } } return null; } private final String[] getThreeValue( final byte[] actionBS, final byte[] bs, final int offset, final int len) { // try { // final String str = new String(bs, offset, len, IConstant.UTF_8); // } catch (final UnsupportedEncodingException e) { // ExceptionReporter.printStackTrace(e); // } final int firstValueIdx = offset + actionBS.length + JSCore.splitBS.length; final int secondSplitIdx = searchNextSplitIndex(bs, firstValueIdx); final String value1 = new String(bs, firstValueIdx, secondSplitIdx - firstValueIdx); final int secondValueIdx = secondSplitIdx + JSCore.splitBS.length; final int threeSplitIdx = searchNextSplitIndex(bs, secondValueIdx); final String value2 = new String(bs, secondValueIdx, threeSplitIdx - secondValueIdx); final int threeValueIdx = threeSplitIdx + JSCore.splitBS.length; final String value3 = new String(bs, threeValueIdx, (len + offset) - threeValueIdx); final String[] out = {JSCore.decode(value1), JSCore.decode(value2), JSCore.decode(value3)}; return out; } private final String[] getTwoValue( final byte[] actionBS, final byte[] bs, final int offset, final int len) { final int firstValueIdx = offset + actionBS.length + JSCore.splitBS.length; final int secondSplitIdx = searchNextSplitIndex(bs, firstValueIdx); final String value1 = new String(bs, firstValueIdx, secondSplitIdx - firstValueIdx); final int secondValueIdx = secondSplitIdx + JSCore.splitBS.length; final String value2 = new String(bs, secondValueIdx, (len + offset) - secondValueIdx); final String[] out = {JSCore.decode(value1), JSCore.decode(value2)}; return out; } private final String getOneValue( final byte[] actionBS, final byte[] bs, final int offset, final int len) { final int firstValueIdx = offset + actionBS.length + JSCore.splitBS.length; final String id = new String(bs, firstValueIdx, len + offset - firstValueIdx); return JSCore.decode(id); } @Override public final void actionExt(final String cmd) { // TODO System.out.println("actionExt : " + cmd); } @Override public final void clickJButton(final int id) { final Component btn = searchComponentByHcCode(mlet, id); // in user thread if (btn != null && btn instanceof AbstractButton) { final MouseEvent e = new MouseEvent( btn, MouseEvent.MOUSE_CLICKED, System.currentTimeMillis(), MouseEvent.BUTTON1_MASK, 0, 0, 1, false); MletSnapCanvas.processClickOnComponent(btn, e); } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } @Override public final void selectSlider(final int id, final int value) { final Component slider = searchComponentByHcCode(mlet, id); if (slider != null && slider instanceof JSlider) { final JSlider sliderBar = (JSlider) slider; if (sliderBar.getValue() == value) { return; } sliderBar.setValue(value); } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } @Override public final void selectComboBox(final int id, final int selectedIndex) { final Component combo = searchComponentByHcCode(mlet, id); if (combo != null && combo instanceof JComboBox) { final JComboBox combo2 = (JComboBox) combo; if (combo2.getSelectedIndex() == selectedIndex) { return; } // final Object oldSelected = combo2.getSelectedItem(); // // //触发ItemEvent[DESELECTED] // if(oldSelected != null){ // final ItemEvent e = new ItemEvent(combo2, ItemEvent.ITEM_STATE_CHANGED, oldSelected, // ItemEvent.DESELECTED); // MCanvas.dispatchEvent(combo, e); // } combo2.setSelectedIndex(selectedIndex); // 注意:执行上步时,会在J2SE环境下自动触发下面两事件和上一行事件。 // java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item=three,stateChange=SELECTED] // java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=comboBoxChanged, // //触发ItemEvent[SELECTED] // { // final Object newSelected = combo2.getItemAt(selectedIndex); // final ItemEvent e = new ItemEvent(combo2, ItemEvent.ITEM_STATE_CHANGED, newSelected, // ItemEvent.SELECTED); // MCanvas.dispatchEvent(combo, e); // } // // //触发ActionEvent // MCanvas.doActon(combo); // java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item=one,stateChange=DESELECTED] // java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item=three,stateChange=SELECTED] // java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=comboBoxChanged, } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } @Override public final void notifyTextFieldValue(final int id, final String value) { final Component combo = searchComponentByHcCode(mlet, id); if (combo != null && combo instanceof JTextField) { final JTextField textField = (JTextField) combo; textField.setText(value); // MCanvas.doActon(combo); } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } @Override public final String toString() { if (mlet != null) { return this.getClass().getSimpleName() + ":" + mlet.getTarget(); } else { return super.toString(); } } @Override public final void notifyTextAreaValue(final int id, final String value) { final Component combo = searchComponentByHcCode(mlet, id); if (combo != null && combo instanceof JComponent && JPanelDiff.isTextMultLinesEditor((JComponent) combo)) { final JTextComponent textArea = (JTextComponent) combo; textArea.setText(value); // MCanvas.doActon(combo); } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } @Override public final void clickJRadioButton(final int id) { final Component combo = searchComponentByHcCode(mlet, id); if (combo != null && combo instanceof JRadioButton) { final JRadioButton radioButton = (JRadioButton) combo; radioButton.doClick(); // MCanvas.doActon(combo); } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } @Override public final void clickJCheckbox(final int id) { final Component combo = searchComponentByHcCode(mlet, id); if (combo != null && combo instanceof JCheckBox) { final JCheckBox checkBox = (JCheckBox) combo; checkBox.doClick(); // MCanvas.doActon(combo); } else { LogManager.err(NO_COMPONENT_HCCODE + id); } } @Override public final Mlet getMlet() { return mlet; } }