1    /*
2    Copyright 2000 by Ralph Hartley
3    This software is licenced under the terms of the
4    Gnu Public Licence
5    */
6    import javax.swing.*;
7    import java.awt.*;
8    import java.awt.geom.*;
9    import java.util.*;
10   import java.awt.event.*;
11   
12   public class CompPane extends JComponent implements Scaleable,MouseListener,MouseMotionListener{
13   
14     public static int NEW = 1;
15     public static int SELECT = 2;
16     public static int SUBSELECT = 3;
17     public static int DELETE = 4;
18     public static int ADD = 5;
19     public static int HAND = 6;
20     public static int ZOOM = 7;
21   
22     public static int MODES = 7;
23     public static int SMOOTH = 8;
24     public static int FLIP = 9;
25   
26     public static int COPY = 10;
27     public static int PASTE = 11;
28   
29     public static double margin = 0.2;
30   
31     public static double screenscale = 0.0025;
32   
33     public Comp contents;
34   
35     public Selection sel = null;
36     public int selindex = 0;
37   
38     Point2D dragpos = new Point2D.Double();
39     Set dragset = null;
40     int dragx = 0;
41     int dragy = 0;
42     int dragrx = 0;
43     int dragry = 0;
44     int dragwidth = 0;
45     int dragheight = 0;
46     boolean dragged;
47     
48     int mode = 0;
49     int command = 0;
50   
51     Class newtype = null;
52     Object newarg = null;
53   
54   //  double scale;
55   //  double rotation;
56   
57     JScrollPane scrollpane;
58   
59     View view = null;
60     ViewTransform viewtrans = new ViewTransform(ViewTransform.ABSOLUTE);
61   
62     CompEditor editor;
63   
64     Fill defaultfill = null;
65     Color defaultcolor = null;
66     LineType defaultlinetype = null;
67     Size defaultlinesize = null;
68     Color defaultlinecolor = null;
69   
70     static Color[] selcolors = {Color.black,Color.red,Color.green,Color.blue};
71     static Color[] invcolors = {Color.white,Color.cyan,Color.magenta,Color.yellow};
72   
73     public CompPane(CompEditor editor) {
74       this.editor = editor;
75   
76   
77       setSelection(0);
78   
79       setOpaque(true);
80       setBackground(Color.white);
81       view = new View(this);
82   //    view.calib = screenscale[0];
83       view.push(viewtrans);
84       view.observer = this;
85       addMouseListener(this);
86       addMouseMotionListener(this);
87       scrollpane = new JScrollPane(this,
88           			 JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
89           			 JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
90       defaultlinetype = LineType.lookup("Generic");
91       defaultlinesize = (Size)FileDefaultable.lookup(Size.class,Size.PIXEL);
92   //    System.out.println("default line size = "+defaultlinesize);
93       defaultlinecolor = Color.black;
94       editor.frame.lastselected = editor;
95     }
96   
97     public Selection setSelection(int index) {
98       selindex = index;
99       sel = editor.frame.carto.selections[index];
100      return(sel);
101    }
102  
103    public void cleanup() {
104      contents = null;
105      dragpos=null;
106      dragset=null;
107      newtype=null;
108      newarg=null;
109      scrollpane=null;
110      view=null;
111      viewtrans=null;
112      editor=null;
113      defaultfill=null;
114      defaultcolor=null;
115      defaultlinetype=null;
116      defaultlinesize=null;
117      defaultlinecolor=null;
118    }
119  
120    public void setLineType(LineType type,Size size,Color color) {
121      if (sel.setLineType(type,size,color))
122        repaint();
123  
124      defaultlinetype = type;
125      defaultlinesize = size;
126      defaultlinecolor = color;
127    }
128  
129    public void setFill(Fill newfill) {
130      if (sel.setFill(newfill))
131        repaint();
132  
133      else defaultfill = newfill;
134    }
135  
136    public void setFill(Color newfill) {
137      if (sel.setFill(newfill))
138        repaint();
139  
140      else defaultcolor = newfill;
141    }
142  
143    public JScrollPane getScrollPane() {
144      return(scrollpane);
145    }
146  
147    Dimension size = new Dimension(500,500);
148  
149    public Dimension getPreferredSize(){
150      return(size);
151    }
152  
153    public Point2D getCenter() {
154      Rectangle viewrect = scrollpane.getViewport().getViewRect();
155      Point2D res = new Point2D.Double();
156      try {
157          viewtrans.inverseTransform(new Point2D.Double(viewrect.getX()+viewrect.getWidth()/2.0,
158          					      viewrect.getY()+viewrect.getHeight()/2.0),res);
159      } catch (java.awt.geom.NoninvertibleTransformException ex) {
160        ErrorLog.exception(ex);
161      }
162      return(res);
163    }
164  
165    public void setScale(double newscale) {
166      Point2D center = getCenter();
167      viewtrans.setScale(newscale,center.getX(),center.getY());
168      adjustSize();
169      repaint();
170    }
171  
172    public void setRotation(double newangle) {
173      Point2D center = getCenter();
174      viewtrans.setRotation(newangle,center.getX(),center.getY());
175      adjustSize();
176      repaint();
177    }
178  
179    public void adjustSize(){
180  
181      Rectangle2D bounds = contents.getBounds(viewtrans);
182      addMargin(bounds);
183      Rectangle viewrect = scrollpane.getViewport().getViewRect();
184  
185      double xtrans = -bounds.getX();
186      double ytrans = -bounds.getY();
187  
188      if (bounds.getWidth()<viewrect.getWidth()) {
189        size.width = (int)viewrect.getWidth();
190        xtrans += (viewrect.getWidth() - bounds.getWidth())/2.0;
191      }
192      else {
193        size.width = (int)bounds.getWidth();
194        viewrect.x -= (int)bounds.getX();
195      }
196  
197      if (bounds.getHeight()<viewrect.getHeight()) {
198        size.height = (int)viewrect.getHeight();
199        ytrans += (viewrect.getHeight() - bounds.getHeight())/2.0;
200      }
201      else {
202        size.height = (int)bounds.getHeight();
203        viewrect.y -= (int)bounds.getY();
204      }
205  
206      setSize(size);
207      viewtrans.preConcatenate(AffineTransform.getTranslateInstance(xtrans,ytrans));
208      view.pop();
209      view.push(viewtrans);
210      scrollpane.getViewport().setViewPosition(new Point(viewrect.x,viewrect.y));
211    }
212  
213    public double center() {
214      Rectangle2D bounds;
215      if (contents.members.isEmpty()) bounds = new Rectangle2D.Double(0.0,0.0,
216          							    size.width,size.height);
217      else {
218        bounds = contents.getBounds(view.trans);
219        addMargin(bounds);
220      }
221      double scale;
222      if (size.width/bounds.getWidth()<size.height/bounds.getHeight())
223        scale=size.width/bounds.getWidth();
224      else
225        scale=size.height/bounds.getHeight();
226      viewtrans.setScale(scale,0.0,0.0);
227      bounds = contents.getBounds(viewtrans);
228      addMargin(bounds);
229      viewtrans.preConcatenate(AffineTransform.getTranslateInstance(
230                (size.width - bounds.getWidth() )/2.0-bounds.getX(),
231                (size.height- bounds.getHeight())/2.0-bounds.getY()));
232      view.pop();
233      view.push(viewtrans);
234      return(scale);
235    }
236  
237    public void paintComponent(Graphics g) {
238      g.setColor(getBackground()); //clear doesn't work because of a java bug (remove in new version)
239      Rectangle clip = g.getClipBounds(); 
240      g.fillRect(clip.x,clip.y,clip.width,clip.height);
241  
242      g.setColor(getForeground());
243      if (contents==null) {
244        Dimension dims = getSize();
245        g.drawLine(0,0,dims.width,dims.height);
246      } else {
247        view.draw = (Graphics2D)g;
248        view.mapscale = new MapScale(view.scale,Unit.pixel,(contents.survey?editor.frame.carto.mapunit:Unit.pixel));
249  //      System.out.println("screenscale = "+screenscale);
250        view.mapscale.metersperpixel = screenscale;
251  
252        view.showall = contents.showall;
253        if (contents.showall) view.visible = Layer.all;
254          else view.visible = contents.visible;
255  
256        view.draw.setColor(Color.black);
257        view.stacking = contents.stack;
258  
259  //      contents.viewChanged();
260        contents.paint(view);
261        contents.getSurvey().paint(view);
262  
263        for (int i=0;i<4;i++) {
264          if (i!=selindex) {
265            view.draw.setColor(selcolors[i]);
266            editor.frame.carto.selections[i].show(view);
267          }
268        }
269  
270        view.draw.setColor(selcolors[selindex]);
271        sel.show(view);
272  /*
273        if (view.showalign) {
274          g.setColor(Comp.alignlinkcolor);
275          for (Iterator it = selection.iterator();it.hasNext();) {
276            Symbol s = (Symbol)it.next();
277            if (s instanceof AlignmentListener)
278              ((AlignmentListener)s).showAlignee(view);
279          }
280          for (Iterator it = subselection.iterator();it.hasNext();) {
281            Symbol s = (Symbol)it.next();
282            if (s instanceof AlignmentListener)
283              ((AlignmentListener)s).showAlignee(view);
284          }
285        }
286  */
287      }
288    }
289  
290    public void addMargin(Rectangle2D dim) {
291  //    System.out.println("margin = "+margin);
292      dim.setRect(dim.getX()-dim.getWidth()*margin/2,
293          	dim.getY()-dim.getHeight()*margin/2,
294          	dim.getWidth()*(1+margin),
295          	dim.getHeight()*(1+margin));
296    }
297  
298    public void setMode(int mode) {
299      this.mode = mode;
300    }
301  
302    Point2D getPos(MouseEvent e) {
303      Point2D pos = new Point2D.Double();
304      try {
305        viewtrans.inverseTransform(e.getPoint(),pos);
306      } catch (java.awt.geom.NoninvertibleTransformException ex) {
307        ErrorLog.exception(ex);
308      }
309      return(pos);
310    }
311  
312    public void mouseClicked(MouseEvent e) {
313    }
314  
315    public void mouseEntered(MouseEvent e) {
316    }
317  
318    public void mouseExited(MouseEvent e) {
319    }
320  
321    public void mousePressed(MouseEvent e) {
322      editor.frame.lastselected = editor;
323  //    editor.requestFocus();
324      editor.frame.dirty = true;
325  
326      Point2D pos = getPos(e);
327      boolean shift = e.isShiftDown();
328      Symbol newselection = null;
329      boolean selecthit = false;
330  
331      if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) {
332        sel.editProperties(contents,shift,pos,view,(mode&MODES)==SUBSELECT);
333        repaint();
334        return;
335      }
336  
337      if ((mode&MODES)!=HAND) {
338        view.draw = (Graphics2D)getGraphics();
339        view.draw = (Graphics2D)view.draw.create();
340        view.draw.setXORMode(invcolors[selindex]);
341      }
342  
343      if ((mode&MODES)==SELECT || (mode&MODES)==SUBSELECT)
344        selecthit = sel.select(contents,shift,pos,view,(mode&MODES)==SUBSELECT);
345  
346      if ((mode&MODES)==NEW && newtype!=null) {
347        newselection = Symbol.getNew(newtype,pos,view,newarg);
348        if (newselection instanceof Curve) {
349          ((Curve)newselection).setFill(defaultcolor);
350          ((Curve)newselection).setLineType(defaultlinetype,defaultlinesize,defaultlinecolor,null);
351        }
352  //      if (newselection!=null) {
353        contents.add(newselection,view);
354        sel.clearSelection();
355        sel.selection.add(newselection);
356        selecthit = true;
357        if (newselection instanceof Addable) {
358          mode=ADD;
359          editor.setMode(ADD);
360        }
361  //      }
362      }
363  
364      if ((mode&MODES)==ADD) {
365        
366        Addable addtarget = sel.getAddable();
367        if (addtarget!=null) {
368          selecthit = true;
369          newselection = Symbol.getNew(addtarget.addType(),pos,view,addtarget);
370          addtarget.add(newselection,sel.subselection,view);
371          sel.clearSubSelection();
372          sel.subselection.add(newselection);
373        }
374      }
375    
376      dragrx = dragx = e.getX();
377      dragry = dragy = e.getY();
378      dragwidth = 0;
379      dragheight = 0;
380      dragged = false;
381      dragpos = pos;
382      if (selecthit)
383        sel.startDrag((mode&MODES)==SELECT);
384      else
385        sel.dragset = null;
386    }
387    
388    public void mouseReleased(MouseEvent e) {
389      if (dragged && (mode&MODES)==ZOOM) {
390        Rectangle oldrect = scrollpane.getViewport().getViewRect();
391        scrollpane.getViewport().
392          setViewPosition(new Point((int)(dragrx+dragwidth/2-oldrect.getWidth()/2),
393          			  (int)(dragry+dragheight/2-oldrect.getHeight()/2)));
394  //      System.out.println("oldrect = "+oldrect);
395  //      System.out.println("drag = ("+dragrx+","+dragry+") ("+dragwidth+","+dragheight+")");
396  //      System.out.println("newrect = "+scrollpane.getViewport().getViewRect());
397  //      System.out .println("oldscale = "+scale+" newscale = "+dragwidth/(oldrect.getWidth()*scale));
398  
399        editor.scale.setValue(viewtrans.scale*oldrect.getWidth()/dragwidth);
400        editor.scale.repaint();
401        setScale(viewtrans.scale*oldrect.getWidth()/dragwidth);
402        return;
403      }
404      repaint();
405      if (!dragged) return;
406  
407      if (!sel.endDrag(getPos(e),mode,view))
408        sel.selectRect(new Rectangle2D.Double(dragrx,dragry,dragwidth,dragheight),
409          			 contents,view,e.isShiftDown());
410    }
411  
412    public void mouseDragged(MouseEvent e) {
413      if ((mode&MODES)==HAND) {
414        Point oldpos = scrollpane.getViewport().getViewPosition();
415        scrollpane.getViewport().setViewPosition(new Point((int)(oldpos.getX()-e.getX()+dragx),
416          						 (int)(oldpos.getY()-e.getY()+dragy)));
417      }
418      else if (!sel.drag(getPos(e),dragged,mode,dragpos,view)) {
419        if (dragged)
420          view.draw.drawRect(dragrx,dragry,dragwidth,dragheight);
421        if (e.getX()<dragx) {
422          dragrx = e.getX();
423          dragwidth = dragx - e.getX();
424        } else {
425          dragrx = dragx;
426          dragwidth = e.getX() - dragx;
427        }
428        if (e.getY()<dragy) {
429          dragry = e.getY();
430          dragheight = dragy - e.getY();
431        } else {
432          dragry = dragy;
433          dragheight = e.getY() - dragy;
434        }
435        view.draw.drawRect(dragrx,dragry,dragwidth,dragheight);      
436      }
437      dragged = true;
438    }
439    
440    public void mouseMoved(MouseEvent e) {
441    }
442  }
443