| /* |
| * Copyright 2000-2009 JetBrains s.r.o. |
| * |
| * 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. |
| */ |
| |
| package com.intellij.uiDesigner.snapShooter; |
| |
| import com.intellij.openapi.vfs.CharsetToolkit; |
| import com.intellij.uiDesigner.XmlWriter; |
| import com.intellij.uiDesigner.radComponents.RadComponent; |
| import com.intellij.uiDesigner.radComponents.RadRootContainer; |
| import com.intellij.util.ArrayUtil; |
| import org.jetbrains.annotations.NonNls; |
| |
| import javax.accessibility.AccessibleContext; |
| import javax.swing.*; |
| import java.awt.*; |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.OutputStreamWriter; |
| import java.net.InetAddress; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| import java.util.*; |
| import java.util.List; |
| import java.util.concurrent.ArrayBlockingQueue; |
| import java.util.concurrent.BlockingQueue; |
| |
| /** |
| * @author yole |
| */ |
| public class SnapShooterDaemon implements Runnable { |
| private final Map<Integer, Component> myIdMap = new HashMap<Integer, Component>(); |
| private int myNextId = 1; |
| private final BlockingQueue<String> myCommandQueue = new ArrayBlockingQueue<String>(20); |
| private final BlockingQueue<String> myResponseQueue = new ArrayBlockingQueue<String>(20); |
| private final int myPort; |
| |
| public SnapShooterDaemon(final int port) { |
| myPort = port; |
| } |
| |
| public void run() { |
| ServerSocket serverSocket; |
| try { |
| serverSocket = new ServerSocket(myPort, 50, InetAddress.getLocalHost()); |
| } |
| catch(IOException ex) { |
| System.out.println("Failed to open server socket: " + ex); |
| return; |
| } |
| |
| System.out.println("SnapShooter listening on port " + myPort); |
| |
| //noinspection InfiniteLoopStatement |
| while (true) { |
| processClientConnection(serverSocket); |
| } |
| } |
| |
| private void processClientConnection(final ServerSocket serverSocket) { |
| Socket clientSocket; |
| try { |
| clientSocket = serverSocket.accept(); |
| System.out.println("SnapShooter connection accepted"); |
| InputStreamReader reader = new InputStreamReader(clientSocket.getInputStream(), CharsetToolkit.UTF8_CHARSET); |
| BufferedReader bufferedReader = new BufferedReader(reader); |
| OutputStreamWriter writer = new OutputStreamWriter(clientSocket.getOutputStream(), CharsetToolkit.UTF8_CHARSET); |
| while(true) { |
| String command; |
| try { |
| command = bufferedReader.readLine(); |
| } |
| catch(IOException ex) { |
| break; |
| } |
| if (command == null) { |
| System.out.println("End of stream receiving command"); |
| break; |
| } |
| processCommand(command, writer); |
| } |
| } |
| catch(IOException ex) { |
| System.out.println("Exception in SnapShooter connection: " + ex); |
| } |
| } |
| |
| private void processCommand(@NonNls final String command, final OutputStreamWriter writer) throws IOException { |
| if (command.startsWith("S")) { |
| SwingUtilities.invokeLater(new SuspendSwingRunnable()); |
| } |
| else { |
| myCommandQueue.add(command); |
| if (command.startsWith("L") || command.startsWith("X")) { |
| String response; |
| try { |
| response = myResponseQueue.take(); |
| } |
| catch (InterruptedException e) { |
| writer.close(); |
| return; |
| } |
| writer.write(response); |
| writer.flush(); |
| } |
| } |
| } |
| |
| private String[] getChildren(final int id) { |
| List<String> result = new ArrayList<String>(); |
| List<Component> children = getChildList(id); |
| for(Component child: children) { |
| SnapShotRemoteComponent rc = new SnapShotRemoteComponent(assignId(child), |
| child.getClass().getName(), |
| getLayoutManagerClass(child), |
| getChildText(child)); |
| result.add(rc.toProtocolString()); |
| } |
| return ArrayUtil.toStringArray(result); |
| } |
| |
| private static String getLayoutManagerClass(final Component component) { |
| if (component instanceof JPanel) { |
| LayoutManager layoutManager = ((Container) component).getLayout(); |
| if (layoutManager != null) { |
| Class layoutManagerClass = layoutManager.getClass(); |
| while(!layoutManagerClass.getSuperclass().equals(Object.class)) { |
| layoutManagerClass = layoutManagerClass.getSuperclass(); |
| } |
| return layoutManagerClass.getName(); |
| } |
| } |
| return ""; |
| } |
| |
| private List<Component> getChildList(final int id) { |
| List<Component> children = new ArrayList<Component>(); |
| if (id == 0) { |
| children = getRootWindows(); |
| } |
| else { |
| Component parent = myIdMap.get(id); |
| if (parent instanceof RootPaneContainer) { |
| RootPaneContainer rpc = (RootPaneContainer) parent; |
| children.add(rpc.getContentPane()); |
| } |
| else if (parent instanceof JSplitPane) { |
| JSplitPane splitPane = (JSplitPane) parent; |
| if (splitPane.getLeftComponent() != null) { |
| children.add(splitPane.getLeftComponent()); |
| } |
| if (splitPane.getRightComponent() != null) { |
| children.add(splitPane.getRightComponent()); |
| } |
| } |
| else if (parent instanceof JScrollPane) { |
| JScrollPane scrollPane = (JScrollPane) parent; |
| children.add(scrollPane.getViewport().getView()); |
| } |
| else if (parent instanceof Container) { |
| Collections.addAll(children, ((Container) parent).getComponents()); |
| } |
| } |
| return children; |
| } |
| |
| private static String getChildText(final Component component) { |
| if (component instanceof Frame) { |
| Frame frame = (Frame) component; |
| return frame.getTitle(); |
| } |
| |
| final AccessibleContext accessibleContext = component.getAccessibleContext(); |
| if (accessibleContext != null) { |
| final String text = accessibleContext.getAccessibleName(); |
| if (text != null && text.length() > 0) { |
| return text; |
| } |
| } |
| |
| return ""; |
| } |
| |
| private int assignId(final Component child) { |
| int result = myNextId; |
| myIdMap.put(result, child); |
| myNextId++; |
| return result; |
| } |
| |
| private static List<Component> getRootWindows() { |
| List<Component> result = new ArrayList<Component>(); |
| for(Frame frame: Frame.getFrames()) { |
| //noinspection HardCodedStringLiteral |
| if (!frame.getClass().getName().endsWith("SwingUtilities$SharedOwnerFrame")) { |
| result.add(frame); |
| } |
| for(Window window: frame.getOwnedWindows()) { |
| if (window.isVisible()) { |
| result.add(window); |
| } |
| } |
| } |
| return result; |
| } |
| |
| private class SuspendSwingRunnable implements Runnable { |
| public void run() { |
| while(true) { |
| String command; |
| try { |
| command = myCommandQueue.take(); |
| } |
| catch (InterruptedException e) { |
| break; |
| } |
| if (command.startsWith("R")) { |
| break; |
| } |
| String response = ""; |
| if (command.startsWith("L")) { |
| response = doListCommand(command); |
| } |
| else if (command.startsWith("X")) { |
| response = doSnapshotCommand(command); |
| } |
| if (response.length() > 0) { |
| System.out.println("Sending response: " + response); |
| try { |
| myResponseQueue.put(response); |
| } |
| catch (InterruptedException e) { |
| break; |
| } |
| } |
| } |
| } |
| |
| @NonNls |
| private String doSnapshotCommand(final String command) { |
| int id = Integer.parseInt(command.substring(1)); |
| Component component = myIdMap.get(id); |
| XmlWriter xmlWriter = new XmlWriter(); |
| RadRootContainer rootContainer = null; |
| try { |
| rootContainer = createFormSnapshot((JComponent) component); |
| } |
| catch (Exception ex) { |
| ex.printStackTrace(); |
| return "E:" + ex.getMessage() + "\n"; |
| } |
| rootContainer.write(xmlWriter); |
| return xmlWriter.getText(); |
| } |
| |
| private RadRootContainer createFormSnapshot(final JComponent component) { |
| SnapshotContext context = new SnapshotContext(); |
| final RadComponent radComponent = RadComponent.createSnapshotComponent(context, component); |
| if (radComponent != null) { |
| radComponent.setBounds(new Rectangle(new Point(10, 10), component.getPreferredSize())); |
| context.getRootContainer().addComponent(radComponent); |
| context.postProcess(); |
| } |
| return context.getRootContainer(); |
| } |
| |
| @NonNls |
| private String doListCommand(final String command) { |
| int id = Integer.parseInt(command.substring(1)); |
| String[] children = getChildren(id); |
| StringBuilder result = new StringBuilder(); |
| for(String child: children) { |
| result.append(child).append("\n"); |
| } |
| result.append(".\n"); |
| return result.toString(); |
| } |
| } |
| } |