Back to index

wims  3.65+svn20090927
KansBoom.java
Go to the documentation of this file.
00001 /*                                                                                                                                         
00002  * A simple diagram editor.                                                                                                                
00003  * Copyright Richard Tobin / HCRC 1996.
00004  *
00005  *
00006  * Sun 8/17/2008 5:22 PM
00007  * > While looking for a lightweight drawing tool (for usage in high school
00008  * > Math. teaching; http://wims.math.leidenuniv.nl/wims/wims.cgi?lang=en) ,I found Your
00009  * > "DiagramEditor.java" to be very suitable !
00010  *
00011  * > My question is: am I allowed to slightly modify** it, compile and use it
00012  * > for building some interactive exercises ?
00013  *
00014  *  Yes, you're welcome to use and modify it.
00015  *
00016  *  It was written in the very early days of Java (1996), so it probably
00017  *  doesn't match current ideas of how to write graphical Java programs.
00018  *
00019  * -- Richard --
00020  * The University of Edinburgh is a charitable body, registered in
00021  * Scotland, with registration number SC005336.
00022  *
00023  *  
00024  *
00025  * This small & fast loading applet was modified with approval of the original author
00026  * for "WIMS interactive usage" 8/2008
00027  * It is mainly used as a simple tool to create / draw a probability tree...
00028  * The sorting produces an easy to check answer for WIMS.
00029  * 
00030  * Changes to the code:
00031  *    - public function ReadApplet() 
00032  *    - tunable through params; see below
00033  *    - language English,Dutch,French,German
00034  *    - using Graphics2 for more modern? looks
00035  *    - added colors [text,shape,background]
00036  *    - removed save & load functionality...
00037  *     
00038  * The original sourcecode is attached at the bottom of this file.
00039  * I renamed the applet to avoid confusion ?
00040  * Test html page:
00041  *    <html>
00042  *     <head></head>
00043  *     <body>
00044  *         <script language="javascript" type="text/javascript">                                                                                      
00045  *            function READTHIS(){                                                                                                                           
00046  *                var input=document.applets[0].ReadApplet();
00047  *                alert("the applet will send:\n"+input);
00048  *            }                                                                                                                                         
00049  *         </script>                                                                                                                                  
00050  *         <center>
00051  *         <applet code="KansBoom.class" archive="KansBoom.jar" width="600" height="400" MAYSCRIPT>
00052  *            <param name="xsize" value="380">
00053  *            <param name="ysize" value="380">
00054  *            <param name="bgcolor" value="255,255,255">
00055  *            <param name="textcolor" value="25,5,5">
00056  *            <param name="drawcolor" value="25,5,150">
00057  *            <param name="penthickness" value="6">
00058  *            <param name="penfontsize" value="66">
00059  *            <param name="penfontfamily" value="Courier">
00060  *            <param name="penfontstyle" value="bold">
00061  *            <param name="language" value="nl">
00062  *            <param name="textlines" value="10">
00063  *            <param name="textalign" value="horizontal">
00064  *         </applet>
00065  *         <input type="button" name=".....TEST......" value=".....TEST....." onclick="javascript:READTHIS();">
00066  *     </body>
00067  *    </html>
00068  *
00069  *                                                                                                  
00070 */
00071 import java.util.*;
00072 import java.awt.*;
00073 import java.applet.*;
00074 
00075 /* The applet itself; contains a display, a control panel and a diagram */
00076 
00077 public class KansBoom extends Applet {
00078     Diagram diagram;
00079     DiagramControls controls;
00080     DiagramDisplay display;
00081     MessageArea message;
00082     EventConsumer current_event_consumer;
00083 
00084 // jm.evers a few defaults...i'm no good at this java :(
00085     static int xsize=640;
00086     static int ysize=480;
00087     static int ygrid=50;// default disabled : less than 50 "lines" of text enables the "snap to line"
00088     static Color bgcolor=new Color(250,250,250);
00089     static Color textcolor=new Color(255,0,0);
00090     static Color drawcolor=new Color(150,0,250);
00091     static float thickness=2.0f;
00092     static int penfontsize=16;
00093     static String fontfamily="Helvetica";
00094     static Font penfont= new Font(fontfamily, Font.BOLD, penfontsize);                                                                         
00095     static Font zoomfont= new Font(fontfamily, Font.BOLD,penfontsize+6);                                                                         
00096     static Font messagefont= new Font(fontfamily, Font.BOLD,16);                                                                         
00097     public String t_line="Line";
00098     public String t_arrow="Arrow";
00099     public String t_rectangle="Rectangle";
00100     public String t_ellipse="Ellipse";
00101     public String t_text="Text";
00102     public String t_circle="Circle";
00103     public String t_destroy="Delete";
00104     public String t_move="Move";
00105     static String t_press="Press return to finish the text";
00106     static boolean textalign=false; // horizontal [snap to y: sort to y] . otherwise vertical [snap to x:sort to x]
00107     static int textcounter=0;
00108     static int linecounter=0;
00109     static boolean original=false;
00110 
00111 //
00112     public void init() {
00113        String param;
00114        param = getParameter("language");
00115        if(param != null) {
00116            if(param.equalsIgnoreCase("nl")){
00117               t_line="lijn";
00118               t_arrow="pijl";
00119               t_rectangle="rechthoek";
00120               t_ellipse="ellips";
00121               t_text="tekst";
00122               t_circle="cirkel";
00123               t_destroy="wissen";
00124               t_move="verplaatsen";
00125               t_press="Druk op enter als de tekst klaar is";
00126            }
00127            if(param.equalsIgnoreCase("de")){
00128               t_line="Linie";
00129               t_arrow="Pfeil";
00130               t_rectangle="Rechteck";
00131               t_ellipse="Ellipse";
00132               t_text="Text";
00133               t_circle="Kreis";
00134               t_destroy="löschen";
00135               t_move="verlagern";
00136               t_press="Drücken Sie auf \"Eingabe\" am Ende des Textes";
00137            }
00138            if(param.equalsIgnoreCase("fr")){
00139               t_line="droite";
00140               t_arrow="flèche";
00141               t_rectangle="rectangle";
00142               t_ellipse="ellips";
00143               t_text="texte";
00144               t_circle="cercle ";
00145               t_destroy="effacer";
00146               t_move="déplacer";
00147               t_press="Press return to finish the text";
00148            }
00149        }
00150        param = getParameter("penfontsize");
00151        if(param != null) {penfontsize=Integer.parseInt(param,10); penfont= new Font("Helvetica", Font.BOLD, penfontsize);}
00152        param = getParameter("penfontfamily");
00153        if(param != null) {penfont= new Font(param, Font.BOLD, penfontsize);}
00154        param = getParameter("penfontstyle");
00155        if(param != null) {
00156            if(param.equalsIgnoreCase("bold")){penfont= new Font(param, Font.BOLD , penfontsize);}
00157            else if(param.equalsIgnoreCase("italic")){penfont= new Font(param, Font.ITALIC , penfontsize);}
00158            else if(param.equalsIgnoreCase("plain")){penfont= new Font(param, Font.PLAIN , penfontsize);}
00159        }
00160        param = getParameter("penthickness");
00161        if(param != null) {thickness=Float.parseFloat(param);}
00162        param = getParameter("xsize");
00163        if(param != null) {xsize=Integer.parseInt(param,10);}
00164        param = getParameter("ysize");
00165        if(param != null) {ysize=Integer.parseInt(param,10);}
00166        param = getParameter("textlines");
00167        if(param != null) {ygrid=Integer.parseInt(param,10);}
00168        param = getParameter("textalign");
00169        if(param == null || param.length()==0){original=true;}else{original=false;if(param.equalsIgnoreCase("vertical")){textalign=true;}else{textalign=false;}}
00170        resize(xsize,ysize);
00171        param=getParameter("bgcolor"); // Background color of inputfield "input"
00172        if (param != null && param.length()>0){
00173            int R1=255;int G1=255;int B1=255;
00174            param=param.replace(':',',');param=param.replace(';',',');
00175            StringTokenizer q = new StringTokenizer(param, ",");
00176            String k;int rgb;
00177            for( int a=0; a<3 ; a++){
00178               k=q.nextToken();
00179               rgb=Integer.parseInt(k, 10);
00180               if(rgb<0){rgb=0;}
00181               if(rgb>255){rgb=255;}
00182               if(a == 0){R1 = rgb;}
00183               else if(a == 1){G1 = rgb;}
00184               else if(a == 2){B1 = rgb;}
00185            }
00186            bgcolor=new Color(R1,G1,B1);
00187        }
00188        param=getParameter("textcolor"); // Background color of inputfield "input"
00189        if (param != null && param.length()>0){
00190            int R2=255;int G2=0;int B2=0;
00191            param=param.replace(':',',');param=param.replace(';',',');
00192            StringTokenizer q = new StringTokenizer(param, ",");
00193            String k;int rgb;
00194            for( int a=0; a<3 ; a++){
00195               k=q.nextToken();
00196               rgb=Integer.parseInt(k, 10);
00197               if(rgb<0){rgb=0;}
00198               if(rgb>255){rgb=255;}
00199               if(a == 0){R2 = rgb;}
00200               else if(a == 1){G2 = rgb;}
00201               else if(a == 2){B2 = rgb;}
00202            }
00203            textcolor=new Color(R2,G2,B2);
00204        }
00205 
00206        param=getParameter("drawcolor"); // Background color of inputfield "input"
00207        if (param != null && param.length()>0){
00208            int R3=255;int G3=255;int B3=0;
00209            param=param.replace(':',',');param=param.replace(';',',');
00210            StringTokenizer q = new StringTokenizer(param, ",");
00211            String k;int rgb;
00212            for( int a=0; a<3 ; a++){
00213               k=q.nextToken();
00214               rgb=Integer.parseInt(k, 10);
00215               if(rgb<0){rgb=0;}
00216               if(rgb>255){rgb=255;}
00217               if(a == 0){R3 = rgb;}
00218               else if(a == 1){G3 = rgb;}
00219               else if(a == 2){B3 = rgb;}
00220            }
00221            drawcolor=new Color(R3,G3,B3);
00222        }
00223        
00224        diagram = new Diagram();
00225        diagram.editor = this;
00226        // no idea how to tell this class that the names are passed on as params in init...
00227        add(controls = new DiagramControls(this ,t_line,t_arrow,t_rectangle,t_ellipse,t_text,t_circle,t_destroy,t_move));
00228        add(display = new DiagramDisplay(this ,penfont,thickness,textcolor,drawcolor,zoomfont));
00229        current_event_consumer = controls;
00230        
00231     }
00232 
00233 // jm.evers        
00234     public String ReadApplet(String arg){
00235        String reply="";
00236        if(arg.equals("1")){
00237            // we sort the text, that should depict a probability tree
00238            // if textaling=true the orientation of the drawing is vertical [left to right ,top to bottom]
00239            //        a
00240            //     b     c
00241            //  d    e f    g 
00242            // becomes: a \n b,c \n d,e,f,g 
00243            // else we expect a horizontal probability tree [top to bottom, left to right]
00244            //       d
00245            //     b  
00246            //       e
00247            //  a     
00248            //       f
00249            //     c  
00250            //       g 
00251            // becomes: a \n b,c \n d,e,f,g 
00252            String line_analysis="";
00253            int[] text_x=new int[textcounter];
00254            int[] text_y=new int[textcounter];
00255            int[] line_x1=new int[linecounter];
00256            int[] line_y1=new int[linecounter];
00257            int[] line_x2=new int[linecounter];
00258            int[] line_y2=new int[linecounter];
00259            String[] tekst=new String[textcounter];
00260            int real_text_length=0;String tmp="";
00261            int real_line_length=0;int x1;int x2;int y1;int y2;
00262            for(Enumeration e = diagram.elements(); e.hasMoreElements(); ){                                                                            
00263               DiagramItem item = (DiagramItem)e.nextElement();
00264               if(item.specify_line_x1() != -1){
00265                   x1=item.specify_line_x1();
00266                   y1=item.specify_line_y1();
00267                   x2=item.specify_line_x2();
00268                   y2=item.specify_line_y2();
00269                   if( x1 != x2 && y1 != y2 ){// avoid line-dots to be send as lines/branches
00270                      line_x1[real_line_length] = x1;
00271                      line_y1[real_line_length] = y1;
00272                      line_x2[real_line_length] = x2;
00273                      line_y2[real_line_length] = y2;
00274                      real_line_length++;
00275                   }
00276               }
00277               if(item.specify_text() != null){
00278                   tmp = item.specify_text();
00279                   // remove the forgotten '_' and we can't use komma's in the reply...replace them by points ?
00280                   tmp =replace(tmp,"_"," ");
00281                   tekst[real_text_length] =replace(tmp,",",".");
00282                   text_x[real_text_length] = item.specify_text_x();
00283                   text_y[real_text_length] = item.specify_text_y();
00284                   real_text_length++;
00285               }
00286            }
00287            boolean online=false;
00288            String[] isonline=new String[real_line_length];boolean found=false;
00289            int items=0;
00290            for(int s=0;s<real_line_length;s++){
00291               found=false;items=0;
00292               for(int r=0;r<real_text_length;r++){
00293                   online=point_near_line(line_x1[s],line_y1[s],line_x2[s],line_y2[s],text_x[r],text_y[r],tekst[r]);
00294                   //System.out.println("tekst "+tekst[r]+" ligt op lijn "+s+" ? : "+online);
00295                   if(online){
00296                      found=true;
00297                      items++;
00298                      if(isonline[s] == null){
00299                          isonline[s]=tekst[r];
00300                      }
00301                      else
00302                      {
00303                          isonline[s]=tekst[r]+","+isonline[s];               
00304                      }
00305                   }
00306               }
00307               if(!found){
00308                   isonline[s]="error_1";//unused_line_error
00309               }
00310 // this gives too many user_errors jm.evers 18/1/2009          
00311 //            else
00312 //            {
00313 //                if(items==1){
00314 //                   isonline[s]=isonline[s]+",error_2";//too_few_items_per_line
00315 //                }
00316 //                else
00317 //                {
00318 //                   if(items>3){
00319 //                       isonline[s]=isonline[s]+",error_3";}//too_many_items_per_line
00320 //                }
00321 //            }
00322            }
00323            
00324            for(int s=0;s<real_line_length;s++){
00325               //System.out.println("line"+s+" : "+isonline[s]);
00326               line_analysis=isonline[s]+"\n"+line_analysis;
00327            }
00328            
00329            if(real_text_length != 2*real_line_length){
00330               if(real_text_length> 2*real_line_length){
00331                   line_analysis=line_analysis+"\nerror_4";//inbalance_too_few_lines
00332               }
00333               else
00334               {
00335                   line_analysis=line_analysis+"\nerror_5";//inbalance_too_many_lines
00336               }
00337            }
00338            if(real_text_length == 0){line_analysis=line_analysis+"\nerror_6";}//text_missing
00339            if(real_line_length == 0){line_analysis=line_analysis+"\nerror_7";}//lines_missing
00340            
00341            boolean nog_meer = true;int i=0;int temp_x;int temp_y;String temp_txt;
00342            nog_meer = true;
00343            String[] sameline = new String[real_text_length];
00344            if(textalign){//horizonal probability tree
00345               while (nog_meer) {
00346                   nog_meer = false;
00347                   for ( i=0; i<real_text_length-1; i++ ){
00348                      if ( text_y[i] < text_y[i+1] ){ sameline[i]="\n";}
00349                      if ( text_y[i] > text_y[i+1] ){
00350                          temp_y = text_y[i]; text_y[i] = text_y[i+1];  text_y[i+1] = temp_y;
00351                          temp_x = text_x[i];  text_x[i] = text_x[i+1];  text_x[i+1] = temp_x;
00352                          temp_txt = tekst[i];  tekst[i] = tekst[i+1];  tekst[i+1] = temp_txt;
00353                          nog_meer = true;
00354                          sameline[i]="\n";
00355                      }
00356                      if ( text_y[i] == text_y[i+1] ){
00357                          sameline[i]=",";
00358                          if( text_x[i] > text_x[i+1] ){
00359                             temp_y = text_y[i]; text_y[i] = text_y[i+1];  text_y[i+1] = temp_y;
00360                              temp_x = text_x[i]; text_x[i] = text_x[i+1];  text_x[i+1] = temp_x;
00361                              temp_txt = tekst[i];  tekst[i] = tekst[i+1];  tekst[i+1] = temp_txt;
00362                             nog_meer = true;
00363                          }
00364                      }
00365                   }
00366               }
00367            }
00368            else
00369            {//vertical probability tree
00370               while (nog_meer) {
00371                   nog_meer = false;
00372                   for ( i=0; i<real_text_length-1; i++ ){
00373                      if ( text_x[i] < text_x[i+1] ){ sameline[i]="\n";}
00374                      if ( text_x[i] > text_x[i+1] ){
00375                          temp_y = text_y[i]; text_y[i] = text_y[i+1];  text_y[i+1] = temp_y;
00376                          temp_x = text_x[i];  text_x[i] = text_x[i+1];  text_x[i+1] = temp_x;
00377                          temp_txt = tekst[i];  tekst[i] = tekst[i+1];  tekst[i+1] = temp_txt;
00378                          nog_meer = true;
00379                          sameline[i]="\n";
00380                      }
00381                      if ( text_x[i] == text_x[i+1] ){
00382                          sameline[i]=",";
00383                          if( text_y[i] > text_y[i+1] ){
00384                             temp_y = text_y[i]; text_y[i] = text_y[i+1];  text_y[i+1] = temp_y;
00385                              temp_x = text_x[i]; text_x[i] = text_x[i+1];  text_x[i+1] = temp_x;
00386                              temp_txt = tekst[i];  tekst[i] = tekst[i+1];  tekst[i+1] = temp_txt;
00387                             nog_meer = true;
00388                          }
00389                      }
00390                   }
00391               }
00392            
00393            }
00394 
00395            for(i=0;i<real_text_length;i++){
00396               if(sameline[i] == null){sameline[i]="\n";}
00397               //reply=reply+tekst[i]+","+text_x[i]+","+text_y[i]+sameline[i];
00398               reply=reply+tekst[i]+sameline[i];
00399            }
00400            reply=reply+"\n@\n"+line_analysis;
00401        }
00402        else
00403        {
00404            //alldata...no special sorting of the text
00405            for(Enumeration e = diagram.elements(); e.hasMoreElements(); ){                                                                            
00406               DiagramItem item = (DiagramItem)e.nextElement();
00407               reply=reply+item.describe()+"\n";
00408            }
00409         }
00410 
00411        return reply;
00412     }
00413     
00414     // replace compatible with java 1.4  [B. Perrin-Riou]
00415     public static String replace(String source, String pattern, String replace){
00416        if (source!=null){
00417            final int len = pattern.length();
00418            StringBuffer sb = new StringBuffer();
00419            int found = -1;
00420            int start = 0;
00421            while( (found = source.indexOf(pattern, start) ) != -1){
00422               sb.append(source.substring(start, found));
00423               sb.append(replace);
00424               start = found + len;
00425            }
00426            sb.append(source.substring(start));
00427            return sb.toString();
00428        }
00429         else return "";
00430     }
00431     // NOT READY: CHECK WHICH POINTS ARE "CONNECTED" WITH THE DRAWN LINES >>>> VERY TRICKY:
00432     //                  /\
00433     //                 /  \
00434     //                A    \ B
00435     //               /      \
00436     //               / C     D\
00437     //              /\        /\
00438     //             /  \      /  \
00439     //            E   F\    G    \H
00440     //           /      \  /      \
00441      
00442     public boolean point_near_line(int lx1, int ly1 , int lx2, int ly2, int px , int py,String text){
00443        // measure distance from point...eg text to a line ,describe by the two end-points
00444        // close enough ? is 4 times the fontsize in pixels: so the margin would be 8xfm ??
00445        // very likely to interfere with sloppy drawings, expected from pupils...
00446        FontMetrics fm =getFontMetrics(penfont);
00447        int w = fm.stringWidth(text);
00448        w=(int)(Math.ceil(w/2));
00449        //System.out.println("x-center begin = "+px);
00450        px=px+w;// px is now the x-center of the string
00451        //System.out.println("x-center  = "+px);
00452        int distance;double ys;double xs;
00453        if( (py > (ly1 - w) && py < (ly2 + w)) || (py > (ly2 - w) && py < (ly1 + w)) ){
00454            if( (px > (lx1 - 2*w) && px < (lx2 + 2*w)) || ( px > (lx2 - 2*w) && px < (lx1 + 2*w)) ){
00455               // the point is in the rect x1y1,x2y2
00456               if( (ly2 - ly1) == 0){
00457                   System.out.println("Horizontal line "); return false;
00458               }
00459               else
00460               {
00461                   if( (lx2 - lx1) == 0 ){
00462                      System.out.println("Vertical line "); return false;
00463                   }
00464                   else
00465                   {  
00466                      ys = (double)(((double)( (px-lx1)*(ly2-ly1)*(lx2-lx1)+(ly2-ly1)*(ly2-ly1)*py+(lx2-lx1)*(lx2-lx1)*ly1 ))/((double)((lx2-lx1)*(lx2-lx1)+(ly2-ly1)*(ly2-ly1))));
00467                      xs = (double)((double)(px))+ys*((double)( (double)(ly1-ly2))/((double)(lx2-lx1))) + ((double)py)*((double)( (double)(ly2-ly1))/((double)(lx2-lx1)));
00468                      distance=(int)(Math.sqrt( (ys - py)*(ys - py) + (xs - px)*(xs - px) ));
00469                      if(distance < 2*w ){return true;}else{return false;}
00470                   }
00471               }
00472            }
00473        }
00474        return false;
00475     }
00476     
00477 
00478     public void start() {
00479     }
00480 
00481     public void stop() {
00482     }
00483 
00484     public void destroy() {
00485     }
00486 
00487     public static void main(String argv[]) {
00488        /* This more-or-less replicates what happens when we  are run as an applet. */
00489        Frame f = new Frame();
00490        KansBoom d = new KansBoom();
00491        d.init();
00492        d.start();
00493        f.add("Center", d);
00494        f.show();
00495     }
00496 }
00497 /* end applet */
00498 
00499 
00500 
00501 /* The diagram */
00502 
00503 class Diagram extends Vector {
00504     KansBoom editor;
00505     DiagramItem nearby(int x, int y){
00506        DiagramItem bestitem = null;
00507        double bestdist = 6;
00508        for(Enumeration e = elements(); e.hasMoreElements(); ) {
00509            DiagramItem item = (DiagramItem)e.nextElement();
00510            double dist = item.distance(x, y);
00511            if(dist < bestdist) {
00512               bestitem = item;
00513               bestdist = dist;
00514            }
00515        }
00516        return bestitem;
00517     }
00518 
00519 }
00520 
00521 
00522 /* The drawing area */
00523 
00524 class DiagramDisplay extends Canvas {
00525     KansBoom editor;
00526     DiagramDisplay(KansBoom ed ,Font penfont, float thickness,Color textcolor,Color drawcolor, Font zoomfont){
00527        editor = ed;
00528        setBackground(KansBoom.bgcolor);
00529        resize(KansBoom.xsize,KansBoom.ysize);
00530     }
00531 
00532 
00533     public void paint(Graphics g) {
00534        Graphics2D g2 = (Graphics2D) g;                                                                                                                    
00535        g2.setFont(KansBoom.penfont);    
00536        g2.setStroke( new BasicStroke(KansBoom.thickness)); 
00537        g2.setColor(KansBoom.drawcolor);
00538        for(Enumeration e = editor.diagram.elements(); e.hasMoreElements(); ) {
00539            ((DiagramItem)e.nextElement()).draw(g2);
00540        }
00541     }
00542     
00543 
00544     public boolean mouseDown(Event e, int x, int y){
00545        if(editor.current_event_consumer.down(x, y)){
00546            repaint();
00547            return true;
00548        } 
00549        else 
00550        {
00551            return false;
00552        }
00553     }
00554 
00555     public boolean mouseUp(Event e, int x, int y){
00556        if(editor.current_event_consumer.up(x, y)){
00557            repaint();
00558            return true;
00559        } 
00560        else 
00561        {
00562            return false;
00563        }
00564     }
00565 
00566     public boolean mouseDrag(Event e, int x, int y){
00567        if(editor.current_event_consumer.drag(x, y)){
00568            repaint();
00569            return true;
00570        } 
00571        else
00572        {
00573            return false;
00574        }
00575     }
00576 
00577     public boolean keyDown(Event e, int key){
00578        if(editor.current_event_consumer.key(key)){
00579            repaint();
00580            return true;
00581        } 
00582        else 
00583        {
00584            return false;
00585        }
00586     }
00587 }
00588 
00589 /* The control panel and the diagram items do things in response to input */
00590 
00591 interface EventConsumer {
00592     public boolean down(int x, int y);
00593     public boolean up(int x, int y);
00594     public boolean drag(int x, int y);
00595     public boolean key(int key);
00596     public void yield();
00597 }
00598 
00599 /* The control panel */
00600 
00601 class DiagramControls extends Panel implements EventConsumer {
00602     KansBoom editor;
00603     CheckboxGroup buttons;
00604     Checkbox line, arrow, rect, ellipse, text, destroy, move;
00605     final int CREATE = 0, DESTROY = 1, MOVE = 2;
00606     
00607 
00608     DiagramControls(KansBoom ed ,String t_line,String t_arrow,String t_rectangle,String t_ellipse,String t_text,String t_circle,String t_destroy,String t_move) {
00609        editor = ed;
00610        setBackground(Color.white);
00611        GridBagLayout gridbag = new GridBagLayout();
00612        GridBagConstraints c = new GridBagConstraints();
00613        Component button;
00614        setLayout(gridbag);
00615        buttons = new CheckboxGroup();
00616        c.gridy = 0;
00617        c.gridx = GridBagConstraints.RELATIVE;
00618        c.anchor = GridBagConstraints.WEST;
00619        button = new DiagramControl(this, CREATE, (new Line()).getClass(), t_line ,  true);
00620        gridbag.setConstraints(button, c);
00621        add(button);
00622        button = new DiagramControl(this, CREATE, (new Arrow()).getClass(), t_arrow ,    false);
00623        gridbag.setConstraints(button, c);
00624        add(button);
00625        button = new DiagramControl(this, CREATE, (new Rect()).getClass(), t_rectangle, false);
00626        gridbag.setConstraints(button, c);
00627        add(button);
00628        button = new DiagramControl(this, CREATE, (new Ellipse()).getClass(), t_ellipse , false);
00629        gridbag.setConstraints(button, c);
00630        add(button);
00631        button = new DiagramControl(this, CREATE, (new Text()).getClass(), t_text ,    false);
00632        gridbag.setConstraints(button, c);
00633        add(button);
00634        c.gridy = 1;
00635        button = new DiagramControl(this, DESTROY, (new Object()).getClass(), t_destroy  , false);
00636        gridbag.setConstraints(button, c);
00637        add(button);
00638        button = new DiagramControl(this, MOVE, (new Object()).getClass(), t_move ,    false);
00639        gridbag.setConstraints(button, c);
00640        add(button);
00641 
00642     }
00643     public boolean down(int x, int y) {
00644        DiagramControl current_button = (DiagramControl)buttons.getCurrent();
00645        DiagramItem target;
00646        Diagram diagram = editor.diagram;
00647        editor.showStatus("");
00648        switch(current_button.mode) {
00649            case CREATE:
00650            try {
00651               Class class_ = current_button.class_;
00652               target = (DiagramItem)class_.newInstance();
00653               target.diagram = diagram;
00654               target.create();
00655               editor.current_event_consumer = target;
00656               diagram.addElement(target);
00657               target.down(x, y);
00658            }
00659            catch (InstantiationException ex) {}
00660            catch (IllegalAccessException ex) {}
00661            return true;
00662            
00663            case DESTROY:
00664            target = diagram.nearby(x, y);
00665            if(target != null) {diagram.removeElement(target);target.destroy();}
00666            return true;
00667            
00668            case MOVE:
00669            target = diagram.nearby(x, y);
00670            if(target != null) {target.move();editor.current_event_consumer = target;target.down(x, y);}
00671            return false;
00672            
00673            default:
00674            return false;
00675        }
00676     }
00677 
00678     public boolean up(int x, int y) {
00679        return false;
00680     }
00681 
00682     public boolean drag(int x, int y) {
00683        return false;
00684     }
00685 
00686     public boolean key(int key) {
00687        return false;
00688     }
00689 
00690     public boolean keyDown(Event e, int key) {
00691        /* For some reason we get the canvas key presses.  Pass them on XXX */
00692        return editor.display.keyDown(e, key);
00693     }
00694 
00695     public void yield() {}
00696 }
00697 
00698 /* The buttons in the control panel */
00699 
00700 class DiagramControl extends Checkbox {
00701     int mode;
00702     Class class_;
00703     DiagramControl(DiagramControls parent, int _mode, Class _class, String label, boolean state) {
00704        super(label, parent.buttons, state);
00705        mode = _mode;
00706        class_ = _class;
00707     }
00708 }
00709 
00710 
00711 /* The diagram items.
00712  * The methods implemented here are suitable for shapes defined by two
00713  * points (ends of a line, corners of an ellipse's bounding box).  Other
00714  * shapes should override.  Maybe I should use a subclass for this, but
00715  * some of the methods may be useful for other shapes (text could use
00716  * these methods for moving but not creating; it would be nice to store the 
00717  * state just by switching the methods).
00718  */
00719 
00720 abstract class DiagramItem implements EventConsumer {
00721     Diagram diagram;
00722     int state;
00723     final int NONE=0, CREATE=1, MOVE=2;
00724     int x, y, w, h;
00725     int movex, movey;
00726     DiagramItem() {
00727        x = y = w = h = 0;
00728     }
00729 
00730     DiagramItem(StringTokenizer tok) throws Exception {
00731        if(tok.countTokens() != 4)
00732        throw new IllegalArgumentException();
00733        x = (new Integer(tok.nextToken())).intValue();
00734        y = (new Integer(tok.nextToken())).intValue();
00735        w = (new Integer(tok.nextToken())).intValue();
00736        h = (new Integer(tok.nextToken())).intValue();
00737     }
00738 
00739     abstract void draw(Graphics g);
00740     abstract String describe();
00741     abstract String specify_text();
00742     abstract int specify_text_x();
00743     abstract int specify_text_y();
00744     abstract int specify_line_x1();
00745     abstract int specify_line_y1();
00746     abstract int specify_line_x2();
00747     abstract int specify_line_y2();
00748 
00749     void create() {
00750        state = CREATE;
00751     }
00752 
00753     public void yield() {
00754        diagram.editor.current_event_consumer = diagram.editor.controls;
00755        state = NONE;
00756     }
00757 
00758     void destroy() {}
00759 
00760     void move() {
00761        state = MOVE;
00762     }
00763 
00764     public boolean down(int _x, int _y) {
00765        switch(state){
00766            case CREATE:
00767            x = _x; y = _y;
00768            return true;
00769            
00770            case MOVE:
00771            movex = _x; movey = _y;
00772            return true;
00773        }
00774        return false;
00775     }
00776 
00777     public boolean up(int _x, int _y) {
00778        switch(state){
00779            case CREATE:
00780            w = _x - x; h = _y - y;
00781            yield();
00782            return true;
00783            
00784            case MOVE:
00785            x += (_x - movex);
00786            y += (_y - movey);
00787            yield();
00788            return true;
00789        }
00790        return false;
00791     }
00792 
00793     public boolean drag(int _x, int _y) {
00794        switch(state){
00795            case CREATE:
00796            w = _x - x; h = _y - y;
00797            return true;
00798        
00799            case MOVE:
00800            x += (_x - movex);
00801            y += (_y - movey);
00802            movex = _x;
00803            movey = _y;
00804            return true;
00805        }
00806        return false;
00807     }
00808 
00809     public boolean key(int key) {
00810        return false;
00811     }
00812 
00813     abstract double distance(int x, int y);
00814 }
00815 
00816 class Ellipse extends DiagramItem {
00817     Ellipse(){super();}
00818     Ellipse(StringTokenizer tok) throws Exception {super(tok);}
00819     String describe() {return "ellipse," + x + "," + y + "," + w + "," + h;}
00820     String specify_text() {return null; }
00821     int specify_text_x() {return -1; }
00822     int specify_text_y() {return -1; }
00823     int specify_line_x1(){return -1;}
00824     int specify_line_y1(){return -1;}
00825     int specify_line_x2(){return -1;}
00826     int specify_line_y2(){return -1;}
00827     void draw(Graphics g) {
00828        g.drawOval(x, y, w, h);
00829     }
00830     double distance(int _x, int _y) {
00831        /* Do this better! */
00832        float ww = w < 1 ? 1 : w, hh = h < 1 ? 1 : h;
00833        float yscale = ww/hh;
00834        float xx = _x - (x + ww / 2);
00835        float yy = (_y - (y + hh / 2)) * yscale;
00836        double r = Math.sqrt(xx * xx + yy * yy);
00837        return Math.abs(r - ww / 2);
00838     }
00839 }
00840 
00841 /* The class name Rectangle is already taken :-( */
00842 
00843 class Rect extends DiagramItem {
00844     Rect(){super();}
00845     Rect(StringTokenizer tok) throws Exception { super(tok);}
00846 
00847     String describe() {return "rectangle," + x + "," + y + "," + (x+w) + "," + (y+h);}
00848     String specify_text() {return null; }
00849     int specify_text_x() {return -1; }
00850     int specify_text_y() {return -1; }
00851     int specify_line_x1(){return -1;}
00852     int specify_line_y1(){return -1;}
00853     int specify_line_x2(){return -1;}
00854     int specify_line_y2(){return -1;}
00855 
00856     void draw(Graphics g) {
00857        g.drawLine(x  , y  , x+w, y  );
00858        g.drawLine(x+w, y  , x+w, y+h);
00859        g.drawLine(x+w, y+h, x  , y+h);
00860        g.drawLine(x  , y+h, x  , y  );
00861     }
00862 
00863     double distance(int _x, int _y) {
00864        double dtop, dbottom, dleft, dright, dist;
00865        if(_x < x){
00866            dtop = Misc.distance(_x, _y, x, y);
00867        }
00868        else 
00869        {
00870            if(_x > x+w){
00871               dtop = Misc.distance(_x, _y, x+w, y);
00872            }
00873            else
00874            {
00875               dtop = Math.abs(_y - y);
00876            }
00877        }    
00878     
00879        if(_x < x){
00880            dbottom = Misc.distance(_x, _y, x, y+h);
00881        }
00882        else
00883        {
00884            if(_x > x+w){
00885               dbottom = Misc.distance(_x, _y, x+w, y+h);
00886            }
00887            else
00888            {
00889               dbottom = Math.abs(_y - (y+h));
00890            }
00891        }
00892        
00893        if(_y < y)
00894            dleft = Misc.distance(_x, _y, x, y);
00895        else if(_y > y+h)
00896            dleft = Misc.distance(_x, _y, x, y+h);
00897        else
00898            dleft = Math.abs(_x - x);
00899     
00900        if(_y < y)
00901            dright = Misc.distance(_x, _y, x+w, y);
00902        else if(_y > y+h)
00903            dright = Misc.distance(_x, _y, x+w, y+h);
00904        else
00905            dright = Math.abs(_x - (x+w));
00906 
00907        dist = dtop;
00908        if(dbottom < dist){dist = dbottom;}
00909        if(dleft < dist){dist = dleft;}
00910        if(dright < dist){dist = dright;}
00911        
00912        return dist;
00913     }
00914 }
00915 
00916 class Line extends DiagramItem {
00917     Line() {super();}
00918     Line(StringTokenizer tok) throws Exception {super(tok);}
00919     void draw(Graphics g) {
00920        Graphics2D g2 = (Graphics2D) g;
00921        if(!KansBoom.original){
00922            int dy=(int) KansBoom.ysize / KansBoom.ygrid;
00923            int dx=(int) KansBoom.xsize / KansBoom.ygrid;
00924            if(state != 2){
00925               y=dy*((int) Math.round(y/dy));
00926               h=dy*((int) Math.round(h/dy));
00927            }
00928            if(state == 1 || state == 2){
00929               g2.setColor(KansBoom.textcolor);
00930               g2.setStroke( new BasicStroke(1.0f));
00931               if(KansBoom.textalign){
00932                   for(int p=0;p<KansBoom.ysize;p=p+dy){
00933                      g2.drawLine(0,p,KansBoom.xsize,p);
00934                   }
00935               }
00936               else
00937               {
00938                   for(int p=0;p<KansBoom.xsize;p=p+dx){
00939                      g2.drawLine(p,0,p,KansBoom.ysize);
00940                   }      
00941               }
00942            }
00943        }
00944        g2.setColor(KansBoom.drawcolor);
00945        g2.setStroke( new BasicStroke(KansBoom.thickness));
00946        g2.drawLine(x, y, x+w, y+h);
00947        KansBoom.linecounter++;
00948     }
00949     String describe() {return "line," + x + "," + y + "," + (x+w) + "," + (y+h);}
00950     String specify_text() {return null; }
00951     int specify_text_x(){return -1; }
00952     int specify_text_y(){return -1; }
00953     int specify_line_x1(){return x;}
00954     int specify_line_y1(){return y;}
00955     int specify_line_x2(){return (x+w);}
00956     int specify_line_y2(){return (y+h);}
00957 
00958     double distance(int _x, int _y) {
00959        if(w == 0 && h == 0)
00960        return Misc.distance(x, y, _x, _y);
00961        /* Set origin to end of line */
00962        _x -= x;
00963        _y -= y;
00964        /* Find line length and unit vector along line */
00965        double len = Math.sqrt(w*w + h*h);
00966        double u = w / len;
00967        double v = h / len;
00968        /* Find nearest point on line using dot product */
00969        double r = _x * u + _y * v;
00970        if(r < 0)
00971            return Misc.distance(0, 0, _x, _y);
00972        if(r > len)
00973            return Misc.distance(w, h, _x, _y);
00974            return Misc.distance(r * u, r * v, _x, _y);
00975     }
00976 }
00977 
00978 class Arrow extends Line {
00979     Arrow(){super();}
00980     Arrow(StringTokenizer tok) throws Exception { super(tok);}
00981     void draw(Graphics g) {
00982        /* Draw a line */
00983        Graphics2D g2 = (Graphics2D) g;
00984        if(!KansBoom.original){
00985            int dy=(int) KansBoom.ysize / KansBoom.ygrid;
00986            int dx=(int) KansBoom.xsize / KansBoom.ygrid;
00987            if( state != 2){
00988               y=dy*((int) Math.round(y/dy));
00989               h=dy*((int) Math.round(h/dy));
00990            }
00991            if(state == 1 || state == 2){
00992               g2.setColor(KansBoom.textcolor);
00993               g2.setStroke( new BasicStroke(1.0f));
00994               if(KansBoom.textalign){
00995                   for(int p=0;p<KansBoom.ysize;p=p+dy){
00996                      g2.drawLine(0,p,KansBoom.xsize,p);
00997                   }
00998               }
00999               else
01000               {
01001                   for(int p=0;p<KansBoom.xsize;p=p+dx){
01002                      g2.drawLine(p,0,p,KansBoom.ysize);
01003                   }      
01004               }
01005            }
01006        }
01007            
01008        KansBoom.linecounter++;
01009        g2.setColor(KansBoom.drawcolor);
01010        g2.setStroke( new BasicStroke(KansBoom.thickness));
01011        g2.drawLine(x, y, x+w, y+h);
01012        if(w == 0 && h == 0){return;}
01013        
01014        /* Find unit vector along line */
01015        double len = Math.sqrt(w*w + h*h);
01016        double u = w / len;
01017        double v = h / len;
01018 
01019        /* Draw arrow head */
01020        double _x = x + w - 5 * u;
01021        double _y = y + h - 5 * v;
01022        g2.drawLine(x+w, y+h, (int)(_x - 5 * v + 0.5), (int)(_y + 5 * u + 0.5));
01023        g2.drawLine(x+w, y+h, (int)(_x + 5 * v + 0.5), (int)(_y - 5 * u + 0.5));
01024     }
01025         
01026     String describe() {return "arrow," + x + "," + y + "," + (x+w) + "," +(y+h);}
01027     String specify_text() {return null; }
01028     int specify_text_x() {return -1; }
01029     int specify_text_y() {return -1; }
01030     int specify_line_x1(){return x;}
01031     int specify_line_y1(){return y;}
01032     int specify_line_x2(){return (x+w);}
01033     int specify_line_y2(){return (y+h);}
01034 
01035 }
01036 
01037 class Text extends DiagramItem {
01038     String text;
01039     StringBuffer buffer;
01040     Text() {
01041        x = y = 0;
01042        buffer = new StringBuffer();
01043        text = buffer.toString().concat("_");
01044     }
01045 
01046     Text(StringTokenizer tok) throws Exception {
01047        if(tok.countTokens() < 1){throw new IllegalArgumentException();}
01048            x = (new Integer(tok.nextToken())).intValue();
01049            y = (new Integer(tok.nextToken())).intValue();
01050            text = tok.nextToken("\n\r").trim();
01051 
01052     }
01053 
01054     void create() {
01055        super.create();
01056        diagram.editor.controls.disable();
01057        //diagram.editor.showStatus("Press return to finish string");
01058        diagram.editor.showStatus(KansBoom.t_press);
01059        KansBoom.textcounter++;
01060     }
01061 
01062     public void yield() {
01063        super.yield();
01064        diagram.editor.controls.enable();
01065        text = buffer.toString();
01066     }
01067 
01068     String describe() {
01069        return "text," + x + "," + y + "," + text;
01070     }
01071     String specify_text() {return text; }
01072     int specify_text_x() {return x; }
01073     int specify_text_y() {return y; }
01074     int specify_line_x1(){return -1;}
01075     int specify_line_y1(){return -1;}
01076     int specify_line_x2(){return -1;}
01077     int specify_line_y2(){return -1;}
01078     
01079 
01080     void draw(Graphics g) {
01081     //jm.evers
01082        if(!KansBoom.original){
01083            Graphics2D g2 = (Graphics2D) g;
01084            int dy=(int) KansBoom.ysize / KansBoom.ygrid;
01085            int dx=(int) KansBoom.xsize / KansBoom.ygrid;
01086            if(state == 1 || state == 2){//show a temp grid lines
01087               g2.setColor(KansBoom.drawcolor);
01088               g2.setStroke( new BasicStroke(1.0f));
01089               if(KansBoom.textalign){for(int p=0;p<KansBoom.ysize;p=p+dy){g2.drawLine(0,p,KansBoom.xsize,p);}}
01090               else{for(int p=0;p<KansBoom.xsize;p=p+dx){g2.drawLine(p,0,p,KansBoom.ysize);}}
01091               g2.setFont(KansBoom.zoomfont);     
01092            }
01093            else
01094            {
01095               g2.setFont(KansBoom.penfont);    
01096            }
01097            if(state != 2){ // not while dragging
01098               if(KansBoom.ygrid<50 && KansBoom.ygrid>1){
01099                   if(KansBoom.textalign){// then snap to the nearest vertical line...
01100                      y=dy*((int) (Math.round(y/dy)));
01101                      if(y<dy){y=dy;}
01102                      if(y>KansBoom.ysize-dy){y=KansBoom.ysize-dy;}
01103                   }
01104                   else
01105                   {//snap to the nearest horizontal line...
01106                      x=dx*((int) (Math.round(x/dx)));
01107                      if(x<dx){x=dx;}
01108                      if(x>KansBoom.xsize-dx){x=KansBoom.xsize-dx;}
01109                   }
01110               }
01111            }
01112            g2.setColor(KansBoom.textcolor);
01113            g2.setStroke( new BasicStroke(KansBoom.thickness));
01114            g2.drawString(text, x, y);
01115            g2.setColor(KansBoom.drawcolor);
01116        }
01117        else
01118        {
01119            g.drawString(text, x, y);
01120        }
01121     }
01122     double distance(int _x, int _y) {
01123        FontMetrics fm = diagram.editor.display.getGraphics().getFontMetrics();
01124        int m = y - (fm.getAscent() / 2);
01125        if(_x < x){return Misc.distance(x, m, _x, _y);}
01126        int r = x + fm.stringWidth(text);
01127        if(_x > r){return Misc.distance(r, m, _x, _y);}
01128        return Math.abs(_y - m);
01129     }
01130 
01131     public boolean down(int _x, int _y) {
01132        switch(state) {
01133            case CREATE:
01134            x = _x; y = _y;
01135            return true;
01136            
01137            case MOVE:
01138            return super.down(_x, _y);
01139        }
01140        return false;
01141     }
01142 
01143     public boolean up(int _x, int _y) {
01144        switch(state) {
01145            case CREATE:
01146            x = _x; y = _y;
01147            return true;
01148            
01149            case MOVE:
01150            return super.up(_x, _y);    
01151        }
01152        return false;
01153     }
01154 
01155     public boolean drag(int _x, int _y) {
01156        switch(state) {
01157            case CREATE:
01158            x = _x; y = _y;
01159            return true;
01160            
01161            case MOVE:
01162            return super.drag(_x, _y);
01163        }
01164        return false;
01165     }
01166 
01167     public boolean key(int key) {
01168        char c[] = new char[1];
01169        switch(state) {
01170            case CREATE:
01171            switch(key) {
01172               case 10:/* LF */
01173 
01174               case 13:/* CR */
01175               yield();
01176               if(text.equals("")){
01177                   diagram.removeElement(this);
01178                   destroy();
01179                   diagram.editor.showStatus("String was empty");
01180               }
01181               else
01182                   diagram.editor.showStatus("");
01183                   return true;
01184               
01185               case 8:/* BS */
01186               case 127:/* DEL */
01187               int l = buffer.length();
01188            if(l > 0)
01189               buffer.setLength(l - 1);
01190               break;
01191     
01192               default:
01193               buffer.append((char)key);
01194               break;
01195            }
01196            text = buffer.toString().concat("_");
01197            return true;
01198        }
01199        return false;
01200     }
01201 }
01202 
01203 /* An area for displaying messages */
01204 
01205 class MessageArea extends Canvas {
01206     String text = "";
01207     void setText(String s) {
01208        text = s;
01209        repaint();
01210     }
01211 
01212     public void paint(Graphics g) {
01213        setBackground(KansBoom.bgcolor);
01214        //g.setFont(KansBoom.messagefont);    
01215        g.drawString(text,5,20);
01216     }
01217 }
01218 
01219 
01220 /* Handy functions */
01221 
01222 class Misc {
01223     static double distance(double x1, double y1, double x2, double y2) {
01224        return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
01225     }
01226 }
01227 
01228 
01230 
01231 /* 
01232  * A simple diagram editor.
01233  * Copyright Richard Tobin / HCRC 1996.
01234  */
01235 
01236 // import java.util.*;
01237 // import java.net.*;
01238 // import java.io.*;
01239 // import java.awt.*;
01240 // import java.applet.*;
01241 // 
01242 /* The applet itself; contains a display, a control panel and a diagram */
01243 // 
01244 // public class DiagramEditor extends Applet {
01245 //     Diagram diagram;
01246 //     DiagramControls controls;
01247 //     DiagramDisplay display;
01248 //     MessageArea message;
01249 // 
01250 //     EventConsumer current_event_consumer;
01251 //     URL loadfrom=null, saveto=null;
01252 // 
01253 //     public void init() {
01254 // String param;
01255 // 
01256 // System.out.println("init called");
01257 // 
01258 // diagram = new Diagram();
01259 // diagram.editor = this;
01260 // add(controls = new DiagramControls(this));
01261 // add(display = new DiagramDisplay(this));
01262 // current_event_consumer = controls;
01263 // 
01264 // param = getParameter("loadfrom");
01265 // if(param != null) {
01266 //     try {
01267 // loadfrom = new URL(getDocumentBase(), param);
01268 //     } catch(MalformedURLException e) {
01269 // showStatus(param + ": " + e.toString());
01270 //     }
01271 // }
01272 // 
01273 // param = getParameter("saveto");
01274 // if(param != null) {
01275 //     try {
01276 // saveto = new URL(getDocumentBase(), param);
01277 //     } catch(Exception e) {
01278 // showStatus(param + ": " + e.toString());
01279 //     }
01280 // }
01281 // else
01282 //     controls.save.disable();
01283 // 
01284 // if(loadfrom != null) {
01285 //     try {
01286 // diagram.load(loadfrom);
01287 //     } catch(Exception e) {
01288 // showStatus("load: " + e.toString());
01289 //     }
01290 // }
01291 // else
01292 //     controls.reload.disable();
01293 // 
01294 // resize(450,300);
01295 //     }
01296 // /*
01297 //     public void paint(Graphics g) {
01298 // System.out.println("paint called");
01299 // g.drawString("Hello world!", 50, 25);
01300 //     }
01301 // */
01302 //     public void start() {
01303 // System.out.println("start called");
01304 //     }
01305 // 
01306 //     public void stop() {
01307 // System.out.println("stop called");
01308 //     }
01309 // 
01310 //     public void destroy() {
01311 // System.out.println("destroy called");
01312 //     }
01313 // 
01314 //     public static void main(String argv[]) {
01315 // System.out.println("main called");
01316 // /* This more-or-less replicates what happens when we
01317 //    are run as an applet. */
01318 // Frame f = new Frame();
01319 // DiagramEditor d = new DiagramEditor();
01320 // d.init();
01321 // d.start();
01322 // f.add("Center", d);
01323 // f.show();
01324 //     }
01325 // }
01326 // 
01327 // /* The diagram */
01328 // 
01329 // class Diagram extends Vector {
01330 //     DiagramEditor editor;
01331 // 
01332 //     DiagramItem nearby(int x, int y) {
01333 // DiagramItem bestitem = null;
01334 // double bestdist = 6;
01335 // 
01336 // for(Enumeration e = elements(); e.hasMoreElements(); ) {
01337 //     DiagramItem item = (DiagramItem)e.nextElement();
01338 //     double dist = item.distance(x, y);
01339 //     if(dist < bestdist) {
01340 // bestitem = item;
01341 // bestdist = dist;
01342 //     }
01343 // }
01344 // 
01345 // return bestitem;
01346 //     }
01347 // 
01348 //     void load(URL source) throws Exception {
01349 // editor.showStatus("Loading from " + source);
01350 // URLConnection conn = source.openConnection();
01351 // DataInputStream inp = new DataInputStream(conn.getInputStream());
01352 // removeAllElements();
01353 // while(true) {
01354 //     String line;
01355 //     if((line = inp.readLine()) != null)
01356 // loadItem(line);
01357 //     else {
01358 // inp.close();
01359 // editor.showStatus("Loaded from " + source);
01360 // return;
01361 //     }
01362 // }
01363 //     }
01364 // 
01365 //     void save(URL dest) throws Exception {
01366 // editor.showStatus("Saving to " + dest);
01367 // 
01368 // /* Send diagram */
01369 // PostConnection conn = new PostConnection(dest);
01370 // String data = "";
01371 // for(Enumeration e = elements(); e.hasMoreElements(); ) {
01372 //     DiagramItem item = (DiagramItem)e.nextElement();
01373 //     data += (item.describe() + "\n");
01374 // }
01375 // conn.send(data);
01376 // 
01377 // /* Read response */
01378 // String line;
01379 // data = "";
01380 // while((line = conn.fromServer.readLine()) != null)
01381 //     data += line;
01382 // editor.showStatus("Saved: " + data);
01383 // 
01384 // conn.close();
01385 //     }
01386 // 
01387 //     void loadItem(String s) throws Exception {
01388 // StringTokenizer tok = new StringTokenizer(s);
01389 // String type = tok.nextToken();
01390 // DiagramItem item;
01391 // 
01392 // if(type.compareTo("line") == 0)
01393 //     item = new Line(tok);
01394 // else if(type.compareTo("arrow") == 0)
01395 //     item = new Arrow(tok);
01396 // else if(type.compareTo("rectangle") == 0)
01397 //     item = new Rect(tok);
01398 // else if(type.compareTo("ellipse") == 0)
01399 //     item = new Ellipse(tok);
01400 // else if(type.compareTo("text") == 0)
01401 //     item = new Text(tok);
01402 // else
01403 //     throw new IllegalArgumentException();
01404 // 
01405 // item.diagram = this;
01406 // addElement(item);
01407 // 
01408 //     }
01409 // }
01410 // 
01411 // /* The drawing area */
01412 // 
01413 // class DiagramDisplay extends Canvas {
01414 //     DiagramEditor editor;
01415 // 
01416 //     DiagramDisplay(DiagramEditor ed) {
01417 // editor = ed;
01418 // setBackground(Color.green);
01419 // resize(450, 200);
01420 //     }
01421 // 
01422 //     public void paint(Graphics g) {
01423 // for(Enumeration e = editor.diagram.elements(); e.hasMoreElements(); ) {
01424 //     ((DiagramItem)e.nextElement()).draw(g);
01425 // }
01426 //     }
01427 // 
01428 //     public boolean mouseDown(Event e, int x, int y) {
01429 // if(editor.current_event_consumer.down(x, y)) {
01430 //     repaint();
01431 //     return true;
01432 // } else {
01433 //     return false;
01434 // }
01435 //     }
01436 // 
01437 //     public boolean mouseUp(Event e, int x, int y) {
01438 // if(editor.current_event_consumer.up(x, y)) {
01439 //     repaint();
01440 //     return true;
01441 // } else {
01442 //     return false;
01443 // }
01444 //     }
01445 // 
01446 //     public boolean mouseDrag(Event e, int x, int y) {
01447 // if(editor.current_event_consumer.drag(x, y)) {
01448 //     repaint();
01449 //     return true;
01450 // } else {
01451 //     return false;
01452 // }
01453 //     }
01454 // 
01455 //     public boolean keyDown(Event e, int key) {
01456 // if(editor.current_event_consumer.key(key)) {
01457 //     repaint();
01458 //     return true;
01459 // } else {
01460 //     return false;
01461 // }
01462 //     }
01463 // }
01464 // 
01465 // /* The control panel and the diagram items do things in response to input */
01466 // 
01467 // interface EventConsumer {
01468 //     public boolean down(int x, int y);
01469 //     public boolean up(int x, int y);
01470 //     public boolean drag(int x, int y);
01471 //     public boolean key(int key);
01472 //     public void yield();
01473 // }
01474 // 
01475 // /* The control panel */
01476 // 
01477 // class DiagramControls extends Panel implements EventConsumer {
01478 //     DiagramEditor editor;
01479 //     CheckboxGroup buttons;
01480 //     Checkbox line, arrow, rect, ellipse, text, destroy, move;
01481 //     SaveButton save;
01482 //     ReloadButton reload;
01483 // 
01484 //     final int CREATE = 0, DESTROY = 1, MOVE = 2;
01485 // 
01486 //     DiagramControls(DiagramEditor ed) {
01487 // editor = ed;
01488 // 
01489 // setBackground(Color.white);
01490 // 
01491 // GridBagLayout gridbag = new GridBagLayout();
01492 // GridBagConstraints c = new GridBagConstraints();
01493 // Component button;
01494 // setLayout(gridbag);
01495 // 
01496 // buttons = new CheckboxGroup();
01497 // 
01498 // c.gridy = 0;
01499 // c.gridx = GridBagConstraints.RELATIVE;
01500 // c.anchor = GridBagConstraints.WEST;
01501 // 
01502 // button = new DiagramControl(this, CREATE, (new Line()).getClass(),
01503 //     "Line",    true);
01504 // gridbag.setConstraints(button, c);
01505 // add(button);
01506 // button = new DiagramControl(this, CREATE, (new Arrow()).getClass(),
01507 //     "Arrow",    false);
01508 // gridbag.setConstraints(button, c);
01509 // add(button);
01510 // button = new DiagramControl(this, CREATE, (new Rect()).getClass(),
01511 //     "Rectangle", false);
01512 // gridbag.setConstraints(button, c);
01513 // add(button);
01514 // button = new DiagramControl(this, CREATE, (new Ellipse()).getClass(),
01515 //     "Ellipse", false);
01516 // gridbag.setConstraints(button, c);
01517 // add(button);
01518 // button = new DiagramControl(this, CREATE, (new Text()).getClass(),
01519 //     "Text",    false);
01520 // gridbag.setConstraints(button, c);
01521 // add(button);
01522 // 
01523 // c.gridy = 1;
01524 // button = new DiagramControl(this, DESTROY, (new Object()).getClass(),
01525 //     "Destroy", false);
01526 // gridbag.setConstraints(button, c);
01527 // add(button);
01528 // button = new DiagramControl(this, MOVE, (new Object()).getClass(),
01529 //     "Move",    false);
01530 // gridbag.setConstraints(button, c);
01531 // add(button);
01532 // 
01533 // c.gridx = 3;
01534 // reload = new ReloadButton(editor.diagram);
01535 // gridbag.setConstraints(reload, c);
01536 // add(reload);
01537 // 
01538 // c.gridx = 4;
01539 // save = new SaveButton(editor.diagram);
01540 // gridbag.setConstraints(save, c);
01541 // add(save);
01542 //     }
01543 // 
01544 //     public boolean down(int x, int y) {
01545 // DiagramControl current_button = (DiagramControl)buttons.getCurrent();
01546 // DiagramItem target;
01547 // Diagram diagram = editor.diagram;
01548 // 
01549 // editor.showStatus("");
01550 // 
01551 // switch(current_button.mode) {
01552 // case CREATE:
01553 //     try {
01554 // Class class_ = current_button.class_;
01555 // target = (DiagramItem)class_.newInstance();
01556 // target.diagram = diagram;
01557 // target.create();
01558 // editor.current_event_consumer = target;
01559 // diagram.addElement(target);
01560 // target.down(x, y);
01561 //     }
01562 //     catch (InstantiationException ex) {}
01563 //     catch (IllegalAccessException ex) {}
01564 //     return true;
01565 // 
01566 // case DESTROY:
01567 //     target = diagram.nearby(x, y);
01568 //     if(target != null) {
01569 // diagram.removeElement(target);
01570 // target.destroy();
01571 //     }
01572 //     return true;
01573 // 
01574 // case MOVE:
01575 //     target = diagram.nearby(x, y);
01576 //     if(target != null) {
01577 // target.move();
01578 // editor.current_event_consumer = target;
01579 // target.down(x, y);
01580 //     }
01581 //     return false;
01582 // 
01583 // default:
01584 //     return false;
01585 // }
01586 //     }
01587 // 
01588 //     public boolean up(int x, int y) {
01589 // return false;
01590 //     }
01591 // 
01592 //     public boolean drag(int x, int y) {
01593 // return false;
01594 //     }
01595 // 
01596 //     public boolean key(int key) {
01597 // return false;
01598 //     }
01599 // 
01600 //     public boolean keyDown(Event e, int key) {
01601 // /* For some reasone we get the canvas key presses.  Pass them on XXX */
01602 // return editor.display.keyDown(e, key);
01603 //     }
01604 // 
01605 //     public void yield() {
01606 //     }
01607 // }
01608 // 
01609 // /* The buttons in the control panel */
01610 // 
01611 // class DiagramControl extends Checkbox {
01612 //     int mode;
01613 //     Class class_;
01614 // 
01615 //     DiagramControl(DiagramControls parent, int _mode, Class _class,
01616 //    String label, boolean state) {
01617 // super(label, parent.buttons, state);
01618 // mode = _mode;
01619 // class_ = _class;
01620 //     }
01621 // }
01622 // 
01623 // class SaveButton extends Button {
01624 //     Diagram diagram;
01625 // 
01626 //     SaveButton(Diagram _diagram) {
01627 // super("Save");
01628 // diagram = _diagram;
01629 //     }
01630 // 
01631 //     public boolean action(Event e, Object arg) {
01632 // diagram.editor.showStatus("");
01633 // try {
01634 //     diagram.save(diagram.editor.saveto);
01635 // } catch (Exception ex) {
01636 //     diagram.editor.showStatus(ex.toString());
01637 // }
01638 // return true;
01639 //     }
01640 // }
01641 // 
01642 // class ReloadButton extends Button {
01643 //     Diagram diagram;
01644 // 
01645 //     ReloadButton(Diagram _diagram) {
01646 // super("Reload");
01647 // diagram = _diagram;
01648 //     }
01649 // 
01650 //     public boolean action(Event e, Object arg) {
01651 // diagram.editor.showStatus("");
01652 // try {
01653 //     diagram.load(diagram.editor.loadfrom);
01654 // } catch (Exception ex) {
01655 //     diagram.editor.showStatus(ex.toString());
01656 // }
01657 // diagram.editor.display.repaint();
01658 // return true;
01659 //     }
01660 // }
01661 // 
01662 // /* The diagram items.
01663 //  * The methods implemented here are suitable for shapes defined by two
01664 //  * points (ends of a line, corners of an ellipse's bounding box).  Other
01665 //  * shapes should override.  Maybe I should use a subclass for this, but
01666 //  * some of the methods may be useful for other shapes (text could use
01667 //  * these methods for moving but not creating; it would be nice to store the 
01668 //  * state just by switching the methods).
01669 //  */
01670 // 
01671 // abstract class DiagramItem implements EventConsumer {
01672 //     Diagram diagram;
01673 //     int state;
01674 //     final int NONE=0, CREATE=1, MOVE=2;
01675 // 
01676 //     int x, y, w, h;
01677 //     int movex, movey;
01678 // 
01679 //     DiagramItem() {
01680 // x = y = w = h = 0;
01681 //     }
01682 // 
01683 //     DiagramItem(StringTokenizer tok) throws Exception {
01684 // if(tok.countTokens() != 4)
01685 //     throw new IllegalArgumentException();
01686 // x = (new Integer(tok.nextToken())).intValue();
01687 // y = (new Integer(tok.nextToken())).intValue();
01688 // w = (new Integer(tok.nextToken())).intValue();
01689 // h = (new Integer(tok.nextToken())).intValue();
01690 //     }
01691 // 
01692 //     abstract void draw(Graphics g);
01693 // 
01694 //     abstract String describe();
01695 // 
01696 //     void create() {
01697 // state = CREATE;
01698 //     }
01699 // 
01700 //     public void yield() {
01701 // diagram.editor.current_event_consumer = 
01702 //     diagram.editor.controls;
01703 // state = NONE;
01704 //     }
01705 // 
01706 //     void destroy() {
01707 //     }
01708 // 
01709 //     void move() {
01710 // state = MOVE;
01711 //     }
01712 // 
01713 //     public boolean down(int _x, int _y) {
01714 // switch(state) {
01715 // case CREATE:
01716 //     x = _x; y = _y;
01717 //     return true;
01718 // case MOVE:
01719 //     movex = _x; movey = _y;
01720 //     return true;
01721 // }
01722 // return false;
01723 //     }
01724 // 
01725 //     public boolean up(int _x, int _y) {
01726 // switch(state) {
01727 // case CREATE:
01728 //     w = _x - x; h = _y - y;
01729 //     yield();
01730 //     return true;
01731 // case MOVE:
01732 //     x += (_x - movex);
01733 //     y += (_y - movey);
01734 //     yield();
01735 //     return true;
01736 // }
01737 // return false;
01738 //     }
01739 // 
01740 //     public boolean drag(int _x, int _y) {
01741 // switch(state) {
01742 // case CREATE:
01743 //     w = _x - x; h = _y - y;
01744 //     return true;
01745 // case MOVE:
01746 //     x += (_x - movex);
01747 //     y += (_y - movey);
01748 //     movex = _x;
01749 //     movey = _y;
01750 //     return true;
01751 // }
01752 // return false;
01753 //     }
01754 // 
01755 //     public boolean key(int key) {
01756 // return false;
01757 //     }
01758 // 
01759 //     abstract double distance(int x, int y);
01760 // }
01761 // 
01762 // class Ellipse extends DiagramItem {
01763 //     Ellipse() {
01764 // super();
01765 //     }
01766 // 
01767 //     Ellipse(StringTokenizer tok) throws Exception {
01768 // super(tok);
01769 //     }
01770 // 
01771 //     String describe() {
01772 // return "ellipse " + x + " " + y + " " + w + " " + h;
01773 //     }
01774 // 
01775 //     void draw(Graphics g) {
01776 // g.drawOval(x, y, w, h);
01777 //     }
01778 // 
01779 //     double distance(int _x, int _y) {
01780 // /* Do this better! */
01781 // float ww = w < 1 ? 1 : w, hh = h < 1 ? 1 : h;
01782 // float yscale = ww/hh;
01783 // float xx = _x - (x + ww / 2);
01784 // float yy = (_y - (y + hh / 2)) * yscale;
01785 // double r = Math.sqrt(xx * xx + yy * yy);
01786 // return Math.abs(r - ww / 2);
01787 //     }
01788 // }
01789 // 
01790 // /* The class name Rectangle is already taken :-( */
01791 // 
01792 // class Rect extends DiagramItem {
01793 //     Rect() {
01794 // super();
01795 //     }
01796 // 
01797 //     Rect(StringTokenizer tok) throws Exception {
01798 // super(tok);
01799 //     }
01800 // 
01801 //     String describe() {
01802 // return "rectangle " + x + " " + y + " " + w + " " + h;
01803 //     }
01804 // 
01805 //     void draw(Graphics g) {
01806 // g.drawLine(x  , y  , x+w, y  );
01807 // g.drawLine(x+w, y  , x+w, y+h);
01808 // g.drawLine(x+w, y+h, x  , y+h);
01809 // g.drawLine(x  , y+h, x  , y  );
01810 //     }
01811 // 
01812 //     double distance(int _x, int _y) {
01813 // double dtop, dbottom, dleft, dright, dist;
01814 // 
01815 // if(_x < x)
01816 //     dtop = Misc.distance(_x, _y, x, y);
01817 // else if(_x > x+w)
01818 //     dtop = Misc.distance(_x, _y, x+w, y);
01819 // else
01820 //     dtop = Math.abs(_y - y);
01821 //     
01822 // if(_x < x)
01823 //     dbottom = Misc.distance(_x, _y, x, y+h);
01824 // else if(_x > x+w)
01825 //     dbottom = Misc.distance(_x, _y, x+w, y+h);
01826 // else
01827 //     dbottom = Math.abs(_y - (y+h));
01828 // 
01829 // if(_y < y)
01830 //     dleft = Misc.distance(_x, _y, x, y);
01831 // else if(_y > y+h)
01832 //     dleft = Misc.distance(_x, _y, x, y+h);
01833 // else
01834 //     dleft = Math.abs(_x - x);
01835 //     
01836 // if(_y < y)
01837 //     dright = Misc.distance(_x, _y, x+w, y);
01838 // else if(_y > y+h)
01839 //     dright = Misc.distance(_x, _y, x+w, y+h);
01840 // else
01841 //     dright = Math.abs(_x - (x+w));
01842 // 
01843 // dist = dtop;
01844 // if(dbottom < dist) dist = dbottom;
01845 // if(dleft < dist) dist = dleft;
01846 // if(dright < dist) dist = dright;
01847 // 
01848 // return dist;
01849 //     }
01850 // }
01851 // 
01852 // class Line extends DiagramItem {
01853 //     Line() {
01854 // super();
01855 //     }
01856 // 
01857 //     Line(StringTokenizer tok) throws Exception {
01858 // super(tok);
01859 //     }
01860 // 
01861 //     String describe() {
01862 // return "line " + x + " " + y + " " + w + " " + h;
01863 //     }
01864 // 
01865 //     void draw(Graphics g) {
01866 // g.drawLine(x, y, x+w, y+h);
01867 //     }
01868 // 
01869 //     double distance(int _x, int _y) {
01870 // if(w == 0 && h == 0)
01871 //     return Misc.distance(x, y, _x, _y);
01872 // 
01873 // /* Set origin to end of line */
01874 // 
01875 // _x -= x;
01876 // _y -= y;
01877 // 
01878 // /* Find line length and unit vector along line */
01879 // double len = Math.sqrt(w*w + h*h);
01880 // double u = w / len;
01881 // double v = h / len;
01882 // 
01883 // /* Find nearest point on line using dot product */
01884 // 
01885 // double r = _x * u + _y * v;
01886 // 
01887 // if(r < 0)
01888 //     return Misc.distance(0, 0, _x, _y);
01889 // if(r > len)
01890 //     return Misc.distance(w, h, _x, _y);
01891 // return Misc.distance(r * u, r * v, _x, _y);
01892 //     }
01893 // }
01894 // 
01895 // class Arrow extends Line {
01896 //     Arrow() {
01897 // super();
01898 //     }
01899 // 
01900 //     Arrow(StringTokenizer tok) throws Exception {
01901 // super(tok);
01902 //     }
01903 // 
01904 //     String describe() {
01905 // return "arrow " + x + " " + y + " " + w + " " + h;
01906 //     }
01907 // 
01908 //     void draw(Graphics g) {
01909 // /* Draw a line */
01910 // g.drawLine(x, y, x+w, y+h);
01911 // if(w == 0 && h == 0)
01912 //     return;
01913 // 
01914 // /* Find unit vector along line */
01915 // double len = Math.sqrt(w*w + h*h);
01916 // double u = w / len;
01917 // double v = h / len;
01918 // 
01919 // /* Draw arrow head */
01920 // double _x = x + w - 5 * u;
01921 // double _y = y + h - 5 * v;
01922 // g.drawLine(x+w, y+h, (int)(_x - 5 * v + 0.5), (int)(_y + 5 * u + 0.5));
01923 // g.drawLine(x+w, y+h, (int)(_x + 5 * v + 0.5), (int)(_y - 5 * u + 0.5));
01924 //     }
01925 // }
01926 // 
01927 // class Text extends DiagramItem {
01928 //     String text;
01929 //     StringBuffer buffer;
01930 // 
01931 //     Text() {
01932 // x = y = 0;
01933 // buffer = new StringBuffer();
01934 // text = buffer.toString().concat("_");
01935 //     }
01936 // 
01937 //     Text(StringTokenizer tok) throws Exception {
01938 // if(tok.countTokens() < 3)
01939 //     throw new IllegalArgumentException();
01940 // x = (new Integer(tok.nextToken())).intValue();
01941 // y = (new Integer(tok.nextToken())).intValue();
01942 // text = tok.nextToken("\n\r").trim();
01943 //     }
01944 // 
01945 //     void create() {
01946 // super.create();
01947 // diagram.editor.controls.disable();
01948 // diagram.editor.showStatus("Press return to finish string");
01949 //     }
01950 // 
01951 //     public void yield() {
01952 // super.yield();
01953 // diagram.editor.controls.enable();
01954 // text = buffer.toString();
01955 //     }
01956 // 
01957 //     String describe() {
01958 // return "text " + x + " " + y + " " + text;
01959 //     }
01960 // 
01961 //     void draw(Graphics g) {
01962 // g.drawString(text, x, y);
01963 //     }
01964 // 
01965 //     double distance(int _x, int _y) {
01966 // FontMetrics fm = diagram.editor.display.getGraphics().getFontMetrics();
01967 // int m = y - (fm.getAscent() / 2);
01968 // if(_x < x)
01969 //     return Misc.distance(x, m, _x, _y);
01970 // int r = x + fm.stringWidth(text);
01971 // if(_x > r)
01972 //     return Misc.distance(r, m, _x, _y);
01973 // return Math.abs(_y - m);
01974 //     }
01975 // 
01976 //     public boolean down(int _x, int _y) {
01977 // switch(state) {
01978 // case CREATE:
01979 //     x = _x; y = _y;
01980 //     return true;
01981 // case MOVE:
01982 //     return super.down(_x, _y);
01983 // }
01984 // return false;
01985 //     }
01986 // 
01987 //     public boolean up(int _x, int _y) {
01988 // switch(state) {
01989 // case CREATE:
01990 //     x = _x; y = _y;
01991 //     return true;
01992 // case MOVE:
01993 //     return super.up(_x, _y);    
01994 // }
01995 // return false;
01996 //     }
01997 // 
01998 //     public boolean drag(int _x, int _y) {
01999 // switch(state) {
02000 // case CREATE:
02001 //     x = _x; y = _y;
02002 //     return true;
02003 // case MOVE:
02004 //     return super.drag(_x, _y);
02005 // }
02006 // return false;
02007 //     }
02008 // 
02009 //     public boolean key(int key) {
02010 // char c[] = new char[1];
02011 // switch(state) {
02012 // case CREATE:
02013 //     switch(key)
02014 //     {
02015 //     case 10:/* LF */
02016 //     case 13:/* CR */
02017 // yield();
02018 // if(text.equals(""))
02019 // {
02020 //     diagram.removeElement(this);
02021 //     destroy();
02022 //     diagram.editor.showStatus("String was empty");
02023 // }
02024 // else
02025 //     diagram.editor.showStatus("");
02026 // return true;
02027 //     case 8:/* BS */
02028 //     case 127:/* DEL */
02029 // int l = buffer.length();
02030 // if(l > 0)
02031 //     buffer.setLength(l - 1);
02032 // break;
02033 //     default:
02034 // buffer.append((char)key);
02035 // break;
02036 //     }
02037 //     text = buffer.toString().concat("_");
02038 //     return true;
02039 // }
02040 // return false;
02041 //     }
02042 // }
02043 // 
02044 // /* An area for displaying messages */
02045 // 
02046 // class MessageArea extends Canvas {
02047 //     String text = "";
02048 // 
02049 //     void setText(String s) {
02050 // text = s;
02051 // repaint();
02052 //     }
02053 // 
02054 //     public void paint(Graphics g) {
02055 // g.drawString(text, 5, 20);
02056 //     }
02057 // }
02058 // 
02059 // /* A class for POST connections */
02060 // 
02061 // class PostConnection {
02062 //     String ctype  = "application/octet-stream";
02063 //     Socket socket;
02064 //     DataInputStream fromServer;
02065 //     DataOutputStream toServer;
02066 //     URL url;
02067 // 
02068 //     PostConnection(URL _url) throws IOException {
02069 // url = _url;
02070 // int port = url.getPort();
02071 // if(port == -1)
02072 //     port = 80;
02073 // System.out.println("connecting to " + url.getHost() + ":" + port);
02074 // socket = new Socket(url.getHost(), port);
02075 // System.out.println("connected");
02076 // fromServer = new DataInputStream(socket.getInputStream());
02077 // toServer = new DataOutputStream(socket.getOutputStream());
02078 //     }
02079 // 
02080 //     void send(String content) throws IOException {
02081 // toServer.writeBytes("POST " + url.getFile() + " HTTP/1.0\r\n");
02082 // toServer.writeBytes("Content-type: " + ctype + "\r\n");
02083 // toServer.writeBytes("Content-length: " + content.length() + "\r\n");
02084 // toServer.writeBytes("\r\n");
02085 // toServer.writeBytes(content);
02086 // toServer.writeBytes("\r\n");
02087 // while(! fromServer.readLine().equals("")) {}
02088 //     }
02089 // 
02090 //     void close() throws IOException {
02091 // fromServer.close();
02092 // toServer.close();
02093 // socket.close();
02094 //     }
02095 // }
02096 // 
02097 // /* Handy functions */
02098 // 
02099 // class Misc {
02100 //     static double distance(double x1, double y1, double x2, double y2) {
02101 // return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
02102 //     }
02103 // }
02104 //