View Javadoc

1   /*
2    *  nextobjects Copyright (C) 2001-2005 Emmanuel Florent
3    *  This program is free software; you can redistribute it and/or modify
4    *  it under the terms of the GNU General Public License as published by the
5    *  Free Software Foundation; either version 2 of the License, or (at your
6    *  option) any later version.
7    *  This program is distributed in the hope that it will
8    *  be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
9    *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10   *  PURPOSE. See the GNU GeneralSys Public License for more details.
11   *  You should have received a copy of the GNU General Public License along
12   *  with this program; if not, write to the Free Software Foundation, Inc., 59
13   *  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14   */
15  package org.devaki.nextobjects.workspace.models.graphics;
16  import java.io.Serializable;
17  import java.awt.BorderLayout;
18  import java.awt.Dimension;
19  import java.awt.Graphics;
20  import java.awt.Graphics2D;
21  import java.awt.Point;
22  import java.awt.Rectangle;
23  import java.awt.image.BufferedImage;
24  import javax.swing.event.ChangeListener;
25  import javax.swing.event.ChangeEvent;
26  import javax.swing.JPanel;
27  import javax.swing.JScrollPane;
28  import org.devaki.nextobjects.constants.CstGraphics;
29  import org.devaki.nextobjects.util.ModelMan;
30  import org.devaki.nextobjects.workspace.models.BaseModel;
31  import org.devaki.nextobjects.workspace.models.objects.BaseObject;
32  import org.devaki.nextobjects.workspace.models.objects.BaseClass;
33  import org.devaki.nextobjects.workspace.models.objects.ModelTitle;
34  import java.awt.Image;
35  /***
36   *  The base for all models
37   *
38   * @author     <a href="mailto:eflorent@devaki.org">Emmanuel Florent</a>
39   * @created    December 22, 2003
40   */
41  public abstract class BaseModelView extends JPanel implements Serializable
42  {
43      /***  X coordinates used when mouse clicking */
44      protected int x1;
45      /***  Y coordinates used when mouse clicking */
46      protected int y1;
47      /***  X coordinates used when mouse draging */
48      protected int x2;
49      /***  Y coordinates used when mouse draging */
50      protected int y2;
51      /***  X difference between x1 and object location */
52      protected int dx;
53      /***  Y difference between x1 and object location */
54      protected int dy;
55      /***  the model bounds */
56      protected Rectangle rectangle;
57      /***  the context model */
58      protected BaseModel myModel;
59      /***  the drawing area */
60      public JPanel drawingArea;
61      /***  the scrollpane */
62      public JScrollPane jScrollPane;
63      /***  the "cartouche" */
64      private ModelTitle modelTitle;
65      /***  full drawing refresh */
66      protected boolean fullRefresh = true;
67      /***  The buffered image */
68      protected transient BufferedImage bi = null;
69  
70  
71      /***
72       *  constructor
73       *
74       * @param  pModel  the model
75       */
76      public BaseModelView(BaseModel pModel)
77      {
78          /***  Initialization * */
79          super(false);
80          // is double buffered!
81          myModel = pModel;
82          modelTitle = new ModelTitle(pModel);
83          pModel.getLabels().addElement(modelTitle.getObjectView());
84          this.setVisible(true);
85          /***  Components * */
86          // Main Panel
87          this.setLayout(new BorderLayout());
88          /***
89           *  There is an inner class. This class is responsible for all the
90           *  executive drawing. The main is paint method. At call the visible
91           *  area is cleared and a prepared BufferedImage is pasted at the top
92           *  left corner. Optionally the very BufferedImage can be rebuilt or
93           *  not. This image is constitued by a set of smaller image generated by
94           *  org.devaki.nextobjects.workspace.models.graphics.* Managing the
95           *  offset can became a hard job.
96           */
97          // Constructor
98          drawingArea =
99              new JPanel()
100             {
101                 /***
102                  *  Draw all components
103                  *
104                  * @param  g  the graphics
105                  */
106                 public void paint(Graphics g)
107                 {
108                     update(g);
109                 }
110 
111 
112                 public Image makeImage(Rectangle pRect)
113                 {
114                 Graphics2D big;
115                 BufferedImage bi2;
116                 Graphics2D bi2g;
117                 ObjectView[] tmp = getVisibleObjectView();
118 
119                     //ObjectView[] tmp = getVisibleObjectView(pRect);
120                     bi =
121                         (BufferedImage) drawingArea.createImage(
122                         pRect.width,
123                         pRect.height);
124                     big = bi.createGraphics();
125                     big.setColor(CstGraphics.MODEL_BACKGROUND_COLOR);
126                     big.fillRect(0, 0, pRect.width, pRect.height);
127                     for (int k = 0; k < tmp.length; k++)
128                     {
129                     // Clears the rectangle that was previously drawn.
130                     Dimension d = tmp[k].getSize();
131                     Point l = tmp[k].getLocation();
132 
133                         if (tmp[k] instanceof ClassView)
134                         {
135                             // classviews
136                             if (d.height > 0 && d.width > 0)
137                             {
138                                 bi2 =
139                                     (BufferedImage) drawingArea.createImage(
140                                     d.width,
141                                     d.height);
142                                 bi2g = bi2.createGraphics();
143                                 tmp[k].paint(bi2g);
144                                 big.drawImage(
145                                     bi2,
146                                     l.x - pRect.x,
147                                     l.y - pRect.y,
148                                     this);
149                             }
150                         }
151                         else
152                         {
153                             //lines
154                             tmp[k].paint(big);
155                         }
156                     }
157                     return bi;
158                 }
159 
160 
161                 public void update(Graphics g)
162                 {
163                 Graphics2D g2 = (Graphics2D) g;
164 
165                     // blank fill, clean ...
166                     super.paintComponent(g2);
167 
168                 //Rectangle area;
169                 Rectangle rect = calculateRectangle();
170 
171                     if (fullRefresh)
172                     {
173                         bi = (BufferedImage) makeImage(rect);
174                         fullRefresh = false;
175                     }
176                     g2.drawImage(bi, rect.x, rect.y, this);
177                     // loop/paint selected objects objects toviewPort panel.
178                     for (int j = 0;
179                         j < ModelMan.getCurrentObjects().size(); j++)
180                     {
181                         ((BaseObject) ModelMan.getCurrentObjects().elementAt(j))
182                             .getObjectView()
183                             .renderSelected(g);
184                     }
185                 }
186             };
187         // resuming normal operations
188         // Define the color of the background
189         this.drawingArea.setBackground(CstGraphics.MODEL_BACKGROUND_COLOR);
190         this.drawingArea.setPreferredSize(CstGraphics.MODEL_DIMENSION);
191         /*
192          *  Assembling components *
193          */
194         this.jScrollPane = new JScrollPane(this.drawingArea);
195         jScrollPane.getViewport().setBackground(
196             CstGraphics.MODEL_BACKGROUND_COLOR);
197         this.add(jScrollPane, BorderLayout.CENTER);
198         //will update the buffered image in case viewport have changed.
199         // used at least at init
200         this.jScrollPane.getViewport().addChangeListener(
201             new ChangeListener()
202             {
203                 public void stateChanged(ChangeEvent e)
204                 {
205                     calculateRectangle();
206                 }
207             });
208         // Initialize scrolling position
209         jScrollPane.getViewport().setViewPosition(
210             CstGraphics.MODEL_INITIAL_POSITION);
211     }
212 
213 
214     /***
215      *  get the visible objects
216      *
217      * @return    the object views
218      */
219     public abstract ObjectView[] getVisibleObjectView();
220 
221 
222     /***
223      *  Return a cached rectangle/bounds for the model
224      *
225      * @return    the rectangle
226      */
227     public Rectangle getRectangle()
228     {
229         if (rectangle == null)
230         {
231             calculateRectangle();
232         }
233         //anyway return previously given rectangle.
234         return rectangle;
235     }
236 
237 
238     /***
239      *  Compute a location point for this viewport to have a centered view of
240      *  the model
241      *
242      * @param  actIt  optiopnaly center the model
243      * @return        the center
244      */
245     public Point center(boolean actIt)
246     {
247         calculateRectangle();
248 
249     Rectangle r1 = this.getRectangle();
250     Rectangle r2 = jScrollPane.getViewport().getViewRect();
251     /*
252      *  //calculate center - formula demonstration .
253      *  Point c1 =
254      *  new Point(
255      *  (r1.x + r1.x + r1.width) / 2,
256      *  (r1.y + r1.y + r1.height) / 2);
257      *  What is the location of the rectangle if the
258      *  center of two rectangle are the same points.
259      *  c2.x  =  (r2.x + r2.x + r2.width) / 2
260      *  2c2.x = (r2.x + r2.x + r2.width )
261      *  2c2.x= 2r2.x + r2.width
262      *  2r2.x = 2c2.x - r2.width
263      *  r2.x = c2.x - (r2.width/2)
264      *  r2.y = c2.y - (r2.height/2)
265      *  and c2 = c1
266      *  r2.x = c1.x - (r2.width/2)
267      *  r2.y = c1.y - (r2.height/2)
268      */
269     Point p =
270             new Point(
271             (r1.x + r1.x + r1.width) / 2 - (r2.width / 2),
272             (r1.y + r1.y + r1.height) / 2 - (r2.height / 2));
273 
274         if (actIt)
275         {
276             jScrollPane.getViewport().setViewPosition(p);
277         }
278         return p;
279     }
280 
281 
282     /***
283      *  Calculate a cached model rectangle
284      *
285      * @return    Description of the Return Value
286      */
287     public Rectangle calculateRectangle()
288     {
289     int xmin = 10000000;
290     int ymin = 10000000;
291     int xmax = 0;
292     int ymax = 0;
293     int xtmpmin = 10000000;
294     int ytmpmin = 10000000;
295     int xtmpmax = 0;
296     int ytmpmax = 0;
297     int delta = 30;
298 
299         for (int i = 0; i < myModel.getClasses().size(); i++)
300         {
301         BaseClass baseObject =
302                 (BaseClass) myModel.getClasses().elementAt(i);
303 
304             xtmpmin = (int) baseObject.getObjectView().getLocation().getX()
305                  - delta;
306             ytmpmin = (int) baseObject.getObjectView().getLocation().getY()
307                  - delta;
308             xtmpmax =
309                 baseObject.getObjectView().getLocation().x
310                  + baseObject.getObjectView().getSize().width + delta;
311             ytmpmax =
312                 baseObject.getObjectView().getLocation().y
313                  + baseObject.getObjectView().getSize().height + delta;
314             if (xtmpmin < xmin)
315             {
316                 xmin = xtmpmin;
317             }
318             if (ytmpmin < ymin)
319             {
320                 ymin = ytmpmin;
321             }
322             if (xtmpmax > xmax)
323             {
324                 xmax = xtmpmax;
325             }
326             if (ytmpmax > ymax)
327             {
328                 ymax = ytmpmax;
329             }
330         }
331         for (int i = 0; i < myModel.getLabels().size(); i++)
332         {
333         ObjectView baseObject =
334                 (ObjectView) myModel.getLabels().elementAt(i);
335 
336             xtmpmin = (int) baseObject.getLocation().getX();
337             ytmpmin = (int) baseObject.getLocation().getY();
338             xtmpmax = baseObject.getLocation().x + baseObject.getSize().width;
339             ytmpmax = baseObject.getLocation().y + baseObject.getSize().height;
340             if (xtmpmin < xmin)
341             {
342                 xmin = xtmpmin;
343             }
344             if (ytmpmin < ymin)
345             {
346                 ymin = ytmpmin;
347             }
348             if (xtmpmax > xmax)
349             {
350                 xmax = xtmpmax;
351             }
352             if (ytmpmax > ymax)
353             {
354                 ymax = ytmpmax;
355             }
356         }
357         rectangle = new Rectangle(xmin, ymin, xmax - xmin, ymax - ymin);
358         return rectangle;
359     }
360 
361 
362     /***
363      *  get the model
364      *
365      * @return    the model
366      */
367     public BaseModel getMyModel()
368     {
369         return myModel;
370     }
371 
372 
373     /***
374      *  set the model
375      *
376      * @param  model  the model
377      */
378     public void setMyModel(BaseModel model)
379     {
380         myModel = model;
381     }
382 
383 
384     /***
385      *  set the dimension
386      *
387      * @param  d  the dimension
388      */
389     public void setViewSize(Dimension d)
390     {
391         jScrollPane.getViewport().setViewSize(d);
392     }
393 
394 
395     /***
396      *  return the view size
397      *
398      * @return    the location
399      */
400     public Dimension getViewSize()
401     {
402         return jScrollPane.getViewport().getViewSize();
403     }
404 
405 
406     /***
407      *  Set if to refresh the drawing at next paint
408      *
409      * @param  b  full refresh
410      */
411     public void setFullRefresh(boolean b)
412     {
413         fullRefresh = b;
414     }
415 
416 
417     /***
418      *  Location of the view position
419      *
420      * @return    the point
421      */
422     public Point getViewPosition()
423     {
424         return jScrollPane.getViewport().getViewPosition();
425     }
426 
427 
428     /***
429      *  Set the view position
430      *
431      * @param  p  the top left corner to clip the drawings.
432      */
433     public void setViewPosition(Point p)
434     {
435         jScrollPane.getViewport().setViewPosition(p);
436     }
437 
438 
439     /***
440      *  get the model title view
441      *
442      * @return    the model "cartouche"
443      */
444     public ModelTitleView getModelTitleView()
445     {
446         return (ModelTitleView) modelTitle.getObjectView();
447     }
448 }
449