2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com
.intellij
.uiDesigner
.snapShooter
;
19 import com
.intellij
.openapi
.vfs
.CharsetToolkit
;
20 import com
.intellij
.uiDesigner
.XmlWriter
;
21 import com
.intellij
.uiDesigner
.radComponents
.RadComponent
;
22 import com
.intellij
.uiDesigner
.radComponents
.RadRootContainer
;
23 import org
.jetbrains
.annotations
.NonNls
;
25 import javax
.accessibility
.AccessibleContext
;
28 import java
.io
.BufferedReader
;
29 import java
.io
.IOException
;
30 import java
.io
.InputStreamReader
;
31 import java
.io
.OutputStreamWriter
;
32 import java
.net
.InetAddress
;
33 import java
.net
.ServerSocket
;
34 import java
.net
.Socket
;
36 import java
.util
.List
;
37 import java
.util
.concurrent
.ArrayBlockingQueue
;
38 import java
.util
.concurrent
.BlockingQueue
;
43 public class SnapShooterDaemon
implements Runnable
{
44 private final Map
<Integer
, Component
> myIdMap
= new HashMap
<Integer
, Component
>();
45 private int myNextId
= 1;
46 private final BlockingQueue
<String
> myCommandQueue
= new ArrayBlockingQueue
<String
>(20);
47 private final BlockingQueue
<String
> myResponseQueue
= new ArrayBlockingQueue
<String
>(20);
48 private final int myPort
;
50 public SnapShooterDaemon(final int port
) {
55 ServerSocket serverSocket
;
57 serverSocket
= new ServerSocket(myPort
, 50, InetAddress
.getLocalHost());
59 catch(IOException ex
) {
60 System
.out
.println("Failed to open server socket: " + ex
);
64 System
.out
.println("SnapShooter listening on port " + myPort
);
66 //noinspection InfiniteLoopStatement
68 processClientConnection(serverSocket
);
72 private void processClientConnection(final ServerSocket serverSocket
) {
75 clientSocket
= serverSocket
.accept();
76 System
.out
.println("SnapShooter connection accepted");
77 InputStreamReader reader
= new InputStreamReader(clientSocket
.getInputStream(), CharsetToolkit
.UTF8_CHARSET
);
78 BufferedReader bufferedReader
= new BufferedReader(reader
);
79 OutputStreamWriter writer
= new OutputStreamWriter(clientSocket
.getOutputStream(), CharsetToolkit
.UTF8_CHARSET
);
83 command
= bufferedReader
.readLine();
85 catch(IOException ex
) {
88 if (command
== null) {
89 System
.out
.println("End of stream receiving command");
92 processCommand(command
, writer
);
95 catch(IOException ex
) {
96 System
.out
.println("Exception in SnapShooter connection: " + ex
);
100 private void processCommand(@NonNls final String command
, final OutputStreamWriter writer
) throws IOException
{
101 if (command
.startsWith("S")) {
102 SwingUtilities
.invokeLater(new SuspendSwingRunnable());
105 myCommandQueue
.add(command
);
106 if (command
.startsWith("L") || command
.startsWith("X")) {
109 response
= myResponseQueue
.take();
111 catch (InterruptedException e
) {
115 writer
.write(response
);
121 private String
[] getChildren(final int id
) {
122 List
<String
> result
= new ArrayList
<String
>();
123 List
<Component
> children
= getChildList(id
);
124 for(Component child
: children
) {
125 SnapShotRemoteComponent rc
= new SnapShotRemoteComponent(assignId(child
),
126 child
.getClass().getName(),
127 getLayoutManagerClass(child
),
128 getChildText(child
));
129 result
.add(rc
.toProtocolString());
131 return result
.toArray(new String
[result
.size()]);
134 private static String
getLayoutManagerClass(final Component component
) {
135 if (component
instanceof JPanel
) {
136 LayoutManager layoutManager
= ((Container
) component
).getLayout();
137 if (layoutManager
!= null) {
138 Class layoutManagerClass
= layoutManager
.getClass();
139 while(!layoutManagerClass
.getSuperclass().equals(Object
.class)) {
140 layoutManagerClass
= layoutManagerClass
.getSuperclass();
142 return layoutManagerClass
.getName();
148 private List
<Component
> getChildList(final int id
) {
149 List
<Component
> children
= new ArrayList
<Component
>();
151 children
= getRootWindows();
154 Component parent
= myIdMap
.get(id
);
155 if (parent
instanceof RootPaneContainer
) {
156 RootPaneContainer rpc
= (RootPaneContainer
) parent
;
157 children
.add(rpc
.getContentPane());
159 else if (parent
instanceof JSplitPane
) {
160 JSplitPane splitPane
= (JSplitPane
) parent
;
161 if (splitPane
.getLeftComponent() != null) {
162 children
.add(splitPane
.getLeftComponent());
164 if (splitPane
.getRightComponent() != null) {
165 children
.add(splitPane
.getRightComponent());
168 else if (parent
instanceof JScrollPane
) {
169 JScrollPane scrollPane
= (JScrollPane
) parent
;
170 children
.add(scrollPane
.getViewport().getView());
172 else if (parent
instanceof Container
) {
173 Collections
.addAll(children
, ((Container
) parent
).getComponents());
179 private static String
getChildText(final Component component
) {
180 if (component
instanceof Frame
) {
181 Frame frame
= (Frame
) component
;
182 return frame
.getTitle();
185 final AccessibleContext accessibleContext
= component
.getAccessibleContext();
186 if (accessibleContext
!= null) {
187 final String text
= accessibleContext
.getAccessibleName();
188 if (text
!= null && text
.length() > 0) {
196 private int assignId(final Component child
) {
197 int result
= myNextId
;
198 myIdMap
.put(result
, child
);
203 private static List
<Component
> getRootWindows() {
204 List
<Component
> result
= new ArrayList
<Component
>();
205 for(Frame frame
: Frame
.getFrames()) {
206 //noinspection HardCodedStringLiteral
207 if (!frame
.getClass().getName().endsWith("SwingUtilities$SharedOwnerFrame")) {
210 for(Window window
: frame
.getOwnedWindows()) {
211 if (window
.isVisible()) {
219 private class SuspendSwingRunnable
implements Runnable
{
224 command
= myCommandQueue
.take();
226 catch (InterruptedException e
) {
229 if (command
.startsWith("R")) {
232 String response
= "";
233 if (command
.startsWith("L")) {
234 response
= doListCommand(command
);
236 else if (command
.startsWith("X")) {
237 response
= doSnapshotCommand(command
);
239 if (response
.length() > 0) {
240 System
.out
.println("Sending response: " + response
);
242 myResponseQueue
.put(response
);
244 catch (InterruptedException e
) {
252 private String
doSnapshotCommand(final String command
) {
253 int id
= Integer
.parseInt(command
.substring(1));
254 Component component
= myIdMap
.get(id
);
255 XmlWriter xmlWriter
= new XmlWriter();
256 RadRootContainer rootContainer
= null;
258 rootContainer
= createFormSnapshot((JComponent
) component
);
260 catch (Exception ex
) {
261 ex
.printStackTrace();
262 return "E:" + ex
.getMessage() + "\n";
264 rootContainer
.write(xmlWriter
);
265 return xmlWriter
.getText();
268 private RadRootContainer
createFormSnapshot(final JComponent component
) {
269 SnapshotContext context
= new SnapshotContext();
270 final RadComponent radComponent
= RadComponent
.createSnapshotComponent(context
, component
);
271 if (radComponent
!= null) {
272 radComponent
.setBounds(new Rectangle(new Point(10, 10), component
.getPreferredSize()));
273 context
.getRootContainer().addComponent(radComponent
);
274 context
.postProcess();
276 return context
.getRootContainer();
280 private String
doListCommand(final String command
) {
281 int id
= Integer
.parseInt(command
.substring(1));
282 String
[] children
= getChildren(id
);
283 StringBuilder result
= new StringBuilder();
284 for(String child
: children
) {
285 result
.append(child
).append("\n");
287 result
.append(".\n");
288 return result
.toString();