Tesseract  3.02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ScrollView.java
Go to the documentation of this file.
1 // Copyright 2007 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); You may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
6 // applicable law or agreed to in writing, software distributed under the
7 // License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
8 // OF ANY KIND, either express or implied. See the License for the specific
9 // language governing permissions and limitations under the License.
10 
11 package com.google.scrollview;
12 
13 import com.google.scrollview.events.SVEvent;
14 import com.google.scrollview.ui.SVImageHandler;
15 import com.google.scrollview.ui.SVWindow;
16 
17 import java.io.BufferedReader;
18 import java.io.IOException;
19 import java.io.InputStreamReader;
20 import java.io.PrintStream;
21 import java.net.ServerSocket;
22 import java.net.Socket;
23 import java.util.ArrayList;
24 import java.util.regex.Pattern;
25 
26 
32 public class ScrollView {
33 
35  public static int SERVER_PORT = 8461;
36 
42  private static Socket socket;
43  private static PrintStream out;
44  public static BufferedReader in;
45  public static float polylineXCoords[]; // The coords being received.
46  public static float polylineYCoords[]; // The coords being received.
47  public static int polylineSize; // The size of the coords arrays.
48  public static int polylineScanned; // The size read so far.
49  private static ArrayList<SVWindow> windows; // The id to SVWindow map.
50  private static Pattern intPattern; // For checking integer arguments.
51  private static Pattern floatPattern; // For checking float arguments.
52 
54  static int nrInputLines = 0;
55 
57  static boolean debugViewNetworkTraffic = false;
58 
60  public static void addMessage(SVEvent e) {
61  if (debugViewNetworkTraffic) {
62  System.out.println("(S->c) " + e.toString());
63  }
64  String str = e.toString();
65  // Send the whole thing as UTF8.
66  try {
67  byte [] utf8 = str.getBytes("UTF8");
68  out.write(utf8, 0, utf8.length);
69  } catch (java.io.UnsupportedEncodingException ex) {
70  System.out.println("Oops... can't encode to UTF8... Exiting");
71  System.exit(0);
72  }
73  out.println();
74  // Flush the output and check for errors.
75  boolean error = out.checkError();
76  if (error) {
77  System.out.println("Connection error. Quitting ScrollView Server...");
78  System.exit(0);
79  }
80  }
81 
83  public static String receiveMessage() throws IOException {
84  return in.readLine();
85  }
86 
91  private static void IOLoop() {
92  String inputLine;
93 
94  try {
95  while (!socket.isClosed() && !socket.isInputShutdown() &&
96  !socket.isOutputShutdown() &&
97  socket.isConnected() && socket.isBound()) {
98  inputLine = receiveMessage();
99  nrInputLines++;
100  if (debugViewNetworkTraffic) {
101  System.out.println("(c->S," + nrInputLines + ")" + inputLine);
102  }
103 
105  // We are processing a polyline.
106  // Read pairs of coordinates separated by commas.
107  boolean first = true;
108  for (String coordStr : inputLine.split(",")) {
109  int coord = Integer.parseInt(coordStr);
110  if (first) {
112  } else {
113  polylineYCoords[polylineScanned++] = coord;
114  }
115  first = !first;
116  }
117  assert first;
118  } else if (SVImageHandler.getReadImageData() == false) {
119  // If we are currently not transmitting an image, process this
120  // normally.
121  processInput(inputLine);
122  }
123  // We are still transmitting image data, but there seems to be some
124  // command at the
125  // end of the message attached as well. Thus, we have to split it
126  // accordingly and
127  // first generate the image and afterwards process the remaining
128  // message.
129  else if (inputLine.length() >
130  SVImageHandler.getMissingRemainingBytes()) {
131  String luaCmd = inputLine.substring(
132  SVImageHandler.getMissingRemainingBytes());
133  String imgData = inputLine.substring(0,
134  SVImageHandler.getMissingRemainingBytes());
135  SVImageHandler.parseData(imgData);
136  processInput(luaCmd);
137  } else { // We are still in the middle of image data and have not
138  // reached the end yet.
139  SVImageHandler.parseData(inputLine);
140  }
141  }
142  }
143  // Some connection error
144  catch (IOException e) {
145  System.out.println("Connection error. Quitting ScrollView Server...");
146  }
147  System.exit(0);
148  }
149 
150  // Parse a comma-separated list of arguments into ArrayLists of the
151  // possible types. Each type is stored in order, but the order
152  // distinction between types is lost.
153  // Note that the format is highly constrained to what the client used
154  // to send to LUA:
155  // Quoted string -> String.
156  // true or false -> Boolean.
157  // %f format number -> Float (no %e allowed)
158  // Sequence of digits -> Integer
159  // Nothing else allowed.
160  private static void parseArguments(String argList,
161  ArrayList<Integer> intList,
162  ArrayList<Float> floatList,
163  ArrayList<String> stringList,
164  ArrayList<Boolean> boolList) {
165  // str is only non-null if an argument starts with a single or double
166  // quote. str is set back to null on completion of the string with a
167  // matching quote. If the string contains a comma then str will stay
168  // non-null across multiple argStr values until a matching closing quote.
169  // Backslash escaped quotes do not count as terminating the string.
170  String str = null;
171  for (String argStr : argList.split(",")) {
172  if (str != null) {
173  // Last string was incomplete. Append argStr to it and restore comma.
174  // Execute str += "," + argStr in Java.
175  int length = str.length() + 1 + argStr.length();
176  StringBuilder appended = new StringBuilder(length);
177  appended.append(str);
178  appended.append(",");
179  appended.append(argStr);
180  str = appended.toString();
181  } else if (argStr.length() == 0) {
182  continue;
183  } else {
184  char quote = argStr.charAt(0);
185  // If it begins with a quote then it is a string, but may not
186  // end this time if it contained a comma.
187  if (quote == '\'' || quote == '"') {
188  str = argStr;
189  }
190  }
191  if (str != null) {
192  // It began with a quote. Check that it still does.
193  assert str.charAt(0) == '\'' || str.charAt(0) == '"';
194  int len = str.length();
195  if (len > 1 && str.charAt(len - 1) == str.charAt(0)) {
196  // We have an ending quote of the right type. Now check that
197  // it is not escaped. Must have an even number of slashes before.
198  int slash = len - 1;
199  while (slash > 0 && str.charAt(slash - 1) == '\\')
200  --slash;
201  if ((len - 1 - slash) % 2 == 0) {
202  // It is now complete. Chop off the quotes and save.
203  // TODO(rays) remove the first backslash of each pair.
204  stringList.add(str.substring(1, len - 1));
205  str = null;
206  }
207  }
208  // If str is not null here, then we have a string with a comma in it.
209  // Append , and the next argument at the next iteration, but check
210  // that str is null after the loop terminates in case it was an
211  // unterminated string.
212  } else if (floatPattern.matcher(argStr).matches()) {
213  // It is a float.
214  floatList.add(Float.parseFloat(argStr));
215  } else if (argStr.equals("true")) {
216  boolList.add(true);
217  } else if (argStr.equals("false")) {
218  boolList.add(false);
219  } else if (intPattern.matcher(argStr).matches()) {
220  // Only contains digits so must be an int.
221  intList.add(Integer.parseInt(argStr));
222  }
223  // else ignore all incompatible arguments for forward compatibility.
224  }
225  // All strings must have been terminated.
226  assert str == null;
227  }
228 
230  private static void processInput(String inputLine) {
231  // Execute a function encoded as a LUA statement! Yuk!
232  if (inputLine.charAt(0) == 'w') {
233  // This is a method call on a window. Parse it.
234  String noWLine = inputLine.substring(1);
235  String[] idStrs = noWLine.split("[ :]", 2);
236  int windowID = Integer.parseInt(idStrs[0]);
237  // Find the parentheses.
238  int start = inputLine.indexOf('(');
239  int end = inputLine.lastIndexOf(')');
240  // Parse the args.
241  ArrayList<Integer> intList = new ArrayList<Integer>(4);
242  ArrayList<Float> floatList = new ArrayList<Float>(2);
243  ArrayList<String> stringList = new ArrayList<String>(4);
244  ArrayList<Boolean> boolList = new ArrayList<Boolean>(3);
245  parseArguments(inputLine.substring(start + 1, end),
246  intList, floatList, stringList, boolList);
247  int colon = inputLine.indexOf(':');
248  if (colon > 1 && colon < start) {
249  // This is a regular function call. Look for the name and call it.
250  String func = inputLine.substring(colon + 1, start);
251  if (func.equals("drawLine")) {
252  windows.get(windowID).drawLine(intList.get(0), intList.get(1),
253  intList.get(2), intList.get(3));
254  } else if (func.equals("createPolyline")) {
255  windows.get(windowID).createPolyline(intList.get(0));
256  } else if (func.equals("drawPolyline")) {
257  windows.get(windowID).drawPolyline();
258  } else if (func.equals("drawRectangle")) {
259  windows.get(windowID).drawRectangle(intList.get(0), intList.get(1),
260  intList.get(2), intList.get(3));
261  } else if (func.equals("setVisible")) {
262  windows.get(windowID).setVisible(boolList.get(0));
263  } else if (func.equals("setAlwaysOnTop")) {
264  windows.get(windowID).setAlwaysOnTop(boolList.get(0));
265  } else if (func.equals("addMessage")) {
266  windows.get(windowID).addMessage(stringList.get(0));
267  } else if (func.equals("addMessageBox")) {
268  windows.get(windowID).addMessageBox();
269  } else if (func.equals("clear")) {
270  windows.get(windowID).clear();
271  } else if (func.equals("setStrokeWidth")) {
272  windows.get(windowID).setStrokeWidth(floatList.get(0));
273  } else if (func.equals("drawEllipse")) {
274  windows.get(windowID).drawEllipse(intList.get(0), intList.get(1),
275  intList.get(2), intList.get(3));
276  } else if (func.equals("pen")) {
277  if (intList.size() == 4) {
278  windows.get(windowID).pen(intList.get(0), intList.get(1),
279  intList.get(2), intList.get(3));
280  } else {
281  windows.get(windowID).pen(intList.get(0), intList.get(1),
282  intList.get(2));
283  }
284  } else if (func.equals("brush")) {
285  if (intList.size() == 4) {
286  windows.get(windowID).brush(intList.get(0), intList.get(1),
287  intList.get(2), intList.get(3));
288  } else {
289  windows.get(windowID).brush(intList.get(0), intList.get(1),
290  intList.get(2));
291  }
292  } else if (func.equals("textAttributes")) {
293  windows.get(windowID).textAttributes(stringList.get(0),
294  intList.get(0),
295  boolList.get(0),
296  boolList.get(1),
297  boolList.get(2));
298  } else if (func.equals("drawText")) {
299  windows.get(windowID).drawText(intList.get(0), intList.get(1),
300  stringList.get(0));
301  } else if (func.equals("openImage")) {
302  windows.get(windowID).openImage(stringList.get(0));
303  } else if (func.equals("drawImage")) {
304  windows.get(windowID).drawImage(stringList.get(0),
305  intList.get(0), intList.get(1));
306  } else if (func.equals("addMenuBarItem")) {
307  if (boolList.size() > 0) {
308  windows.get(windowID).addMenuBarItem(stringList.get(0),
309  stringList.get(1),
310  intList.get(0),
311  boolList.get(0));
312  } else if (intList.size() > 0) {
313  windows.get(windowID).addMenuBarItem(stringList.get(0),
314  stringList.get(1),
315  intList.get(0));
316  } else {
317  windows.get(windowID).addMenuBarItem(stringList.get(0),
318  stringList.get(1));
319  }
320  } else if (func.equals("addPopupMenuItem")) {
321  if (stringList.size() == 4) {
322  windows.get(windowID).addPopupMenuItem(stringList.get(0),
323  stringList.get(1),
324  intList.get(0),
325  stringList.get(2),
326  stringList.get(3));
327  } else {
328  windows.get(windowID).addPopupMenuItem(stringList.get(0),
329  stringList.get(1));
330  }
331  } else if (func.equals("update")) {
332  windows.get(windowID).update();
333  } else if (func.equals("showInputDialog")) {
334  windows.get(windowID).showInputDialog(stringList.get(0));
335  } else if (func.equals("showYesNoDialog")) {
336  windows.get(windowID).showYesNoDialog(stringList.get(0));
337  } else if (func.equals("zoomRectangle")) {
338  windows.get(windowID).zoomRectangle(intList.get(0), intList.get(1),
339  intList.get(2), intList.get(3));
340  } else if (func.equals("createImage")) {
341  windows.get(windowID).createImage(stringList.get(0), intList.get(0),
342  intList.get(1), intList.get(2));
343  } else if (func.equals("drawImage")) {
344  windows.get(windowID).drawImage(stringList.get(0),
345  intList.get(0), intList.get(1));
346  } else if (func.equals("destroy")) {
347  windows.get(windowID).destroy();
348  }
349  // else for forward compatibility purposes, silently ignore any
350  // unrecognized function call.
351  } else {
352  // No colon. Check for create window.
353  if (idStrs[1].startsWith("= luajava.newInstance")) {
354  while (windows.size() <= windowID) {
355  windows.add(null);
356  }
357  windows.set(windowID, new SVWindow(stringList.get(1),
358  intList.get(0), intList.get(1),
359  intList.get(2), intList.get(3),
360  intList.get(4), intList.get(5),
361  intList.get(6)));
362  }
363  // else for forward compatibility purposes, silently ignore any
364  // unrecognized function call.
365  }
366  } else if (inputLine.startsWith("svmain")) {
367  // Startup or end. Startup is a lua bind, which is now a no-op.
368  if (inputLine.startsWith("svmain:exit")) {
369  exit();
370  }
371  // else for forward compatibility purposes, silently ignore any
372  // unrecognized function call.
373  }
374  // else for forward compatibility purposes, silently ignore any
375  // unrecognized function call.
376  }
377 
379  public static void exit() {
380  System.exit(0);
381  }
382 
387  public static void main(String[] args) {
388  if (args.length > 0) {
389  SERVER_PORT = Integer.parseInt(args[0]);
390  }
391  windows = new ArrayList<SVWindow>(100);
392  intPattern = Pattern.compile("[0-9-][0-9]*");
393  floatPattern = Pattern.compile("[0-9-][0-9]*\\.[0-9]*");
394 
395  try {
396  // Open a socket to listen on.
397  ServerSocket serverSocket = new ServerSocket(SERVER_PORT);
398  System.out.println("Socket started on port " + SERVER_PORT);
399 
400  // Wait (blocking) for an incoming connection
401  socket = serverSocket.accept();
402  System.out.println("Client connected");
403 
404  // Setup the streams
405  out = new PrintStream(socket.getOutputStream(), true);
406  in =
407  new BufferedReader(new InputStreamReader(socket.getInputStream(),
408  "UTF8"));
409  } catch (IOException e) {
410  // Something went wrong and we were unable to set up a connection. This is
411  // pretty
412  // much a fatal error.
413  // Note: The server does not get restarted automatically if this happens.
414  e.printStackTrace();
415  System.exit(1);
416  }
417 
418  // Enter the main program loop.
419  IOLoop();
420  }
421 }