KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > gui > graph > view > BasicComponentRenderer


1 /***
2  * FractalGUI: a graphical tool to edit Fractal component configurations.
3  * Copyright (C) 2003 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Contact: fractal@objectweb.org
20  *
21  * Authors: Eric Bruneton, Patrice Fauvel
22  */

23
24 package org.objectweb.fractal.gui.graph.view;
25
26 import org.objectweb.fractal.gui.Constants;
27 import org.objectweb.fractal.gui.model.ClientInterface;
28 import org.objectweb.fractal.gui.model.Component;
29 import org.objectweb.fractal.gui.model.Interface;
30 import org.objectweb.fractal.gui.selection.model.Selection;
31
32 import java.awt.Color JavaDoc;
33 import java.awt.FontMetrics JavaDoc;
34 import java.awt.Graphics JavaDoc;
35 import java.awt.Graphics2D JavaDoc;
36 import java.awt.Point JavaDoc;
37 import java.awt.Rectangle JavaDoc;
38 import java.awt.Shape JavaDoc;
39 import java.util.List JavaDoc;
40
41 /**
42  * Basic implementation of the {@link ComponentRenderer} interface. This
43  * implementation draws components as illustrated in the figure below.
44  *
45  * <center><img SRC="../../../../../../../figures/crenderer.gif"/></center>
46  */

47
48 public class BasicComponentRenderer implements
49   ComponentRenderer,
50   Constants
51 {
52
53   /**
54    * Maximum h of an interface, insets included. In other words, maximum
55    * value of {@link #divH}.
56    */

57
58     private final static int MAX_DIV = 16;
59
60   /**
61    * Vertical space between interfaces, and horizontal space between interface
62    * names and component frame.
63    */

64
65     private final static int INSETS = 2;
66
67   /**
68    * Maximum distance under which two points are considered equal in
69    * {@link #isCorner} and {@link #isBorder}.
70    */

71
72     private final static int EPS = 4;
73
74   /**
75    * The component for which the current values of the fields of this object
76    * have been computed. This field is used to avoid recomputing these values
77    * if it is not necessary.
78    */

79
80     Component c;
81
82   /**
83    * The component position for which the current values of the fields of this
84    * object have been computed. This field is used to avoid recomputing these
85    * values if it is not necessary.
86    */

87
88     Rectangle JavaDoc r;
89
90   /**
91    * Left border of the rectangle into which the component is drawn.
92    */

93
94     int x;
95
96   /**
97    * Top border of the rectangle into which the component is drawn.
98    */

99
100     int y;
101
102   /**
103    * Width of the rectangle into which the component is drawn.
104    */

105
106     int w;
107
108   /**
109    * Height of the rectangle into which the component is drawn.
110    */

111
112     int h;
113
114   /**
115    * List of the external server interfaces of the component that is drawn.
116    */

117
118     List JavaDoc sItfList;
119
120   /**
121    * List of the external client interfaces of the component that is drawn.
122    */

123
124     List JavaDoc cItfList;
125
126   /**
127    * Size of the component's frame. See above figure.
128    */

129
130     int borderSize;
131
132   /**
133    * Height of interfaces, including spaces between them. See above figure.
134    */

135
136   int divH;
137
138   /**
139    * Height of interfaces. See above figure.
140    */

141
142   int itfH;
143
144   /**
145    * Width of interfaces. See above figure.
146    */

147
148   int itfW;
149
150   /**
151    * itfW + INSETS. See above figure.
152    */

153
154   int itfWi;
155
156   /**
157    * itfW + borderSize. See above figure.
158    */

159
160   int bw1;
161
162   /**
163    * itfW + borderSize + itfW. See above figure.
164    */

165
166   int bw2;
167
168   /**
169    * itfW + borderSize + itfW + INSETS. See above figure.
170    */

171
172   int bw3;
173
174   /**
175    * Constructs a new {@link BasicComponentRenderer} component.
176    */

177
178   public BasicComponentRenderer () {
179   }
180
181     // -------------------------------------------------------------------------
182
// Implementation of the ComponentRenderer interface
183
// -------------------------------------------------------------------------
184

185     public void drawComponent (
186     final Graphics JavaDoc g,
187     final Component c,
188     final Selection s,
189     final Rectangle JavaDoc r,
190     final Color JavaDoc color,
191     final boolean expanded,
192     final int mode,
193     final int state)
194   {
195         initialize(c, r);
196         Object JavaDoc sel = (s == null ? null : s.getSelection());
197
198         // draw component frame
199
g.translate(x, y);
200         if (c.getMasterComponent() != null && sel != c) {
201             ((Graphics2D JavaDoc)g).setStroke(DASHED_STROKE);
202         } else {
203             ((Graphics2D JavaDoc)g).setStroke(NORMAL_STROKE);
204         }
205
206 /*
207         g.setColor(color);
208         g.fillRect(itfW, 0, w - 2*itfW, h);
209         g.setColor(sel == c ? SELECTION_COLOR : Color.black);
210         g.drawRect(itfW, 0, w-2*itfW-1, h-1);
211
212         if (sel == c) {
213            g.drawRect(itfW - 1, -1, w - 2*itfW + 1, h + 1);
214         }
215 */

216
217     int [] PXO = {itfW+4, itfW+w-2*itfW+3, itfW+w-2*itfW+3, itfW+11, itfW+4 };
218     int [] PYO = {4, 4, h+3, h+3, h-4 };
219     g.setColor(Color.lightGray);
220     g.fillPolygon(PXO, PYO, 5);
221     int [] PX = {itfW, itfW+w-2*itfW-1, itfW+w-2*itfW-1, itfW+7, itfW };
222     int [] PY = {0, 0, h-1, h-1, h-8 };
223     int [] PXS = {itfW-1, itfW+w-2*itfW, itfW+w-2*itfW, itfW+7, itfW-1 };
224     int [] PYS = {-1, -1, h, h, h-8 };
225         g.setColor(color);
226     g.fillPolygon(PX, PY, 5);
227         g.setColor(sel == c ? SELECTION_COLOR : Color.black);
228     g.drawPolygon(PX, PY, 5);
229         if (sel == c) {
230       g.drawPolygon(PXS, PYS, 5);
231         }
232
233         if (c.isComposite()) {
234           g.setColor(Color.white);
235           g.fillRect(bw1, borderSize, w-2*bw1, h-2*borderSize);
236           g.setColor(Color.black);
237           g.drawRect(bw1, borderSize, w-2*bw1-1, h-2*borderSize-1);
238         }
239
240     g.setColor(color);
241     if (state != NO_INSTANCE) {
242       int [] TX = {itfW, itfW+9, itfW+9, itfW+7 };
243       int [] TY = {h-9, h-9, h-1, h-1 };
244       if (state == STARTED) {
245         g.setColor(Color.green);
246       } else if (state == STOPPED) {
247         g.setColor(Color.red);
248       }
249       g.fillPolygon(TX, TY, 4);
250       g.setColor(Color.black);
251       g.drawPolygon(TX, TY, 4);
252     }
253
254         if (!expanded) {
255            // draw pseudo sub components ?
256
}
257 /*
258     // ----- ADMIN
259     if (state != NO_INSTANCE) {
260       if (state == STARTED) {
261         g.setColor(Color.green);
262 // g.fillRect(w-bw1+1, 2, 8, 8);
263         g.fillRect(w-bw1-6, 0, 8, 8);
264       } else if (state == STOPPED) {
265         g.setColor(Color.red);
266         g.fillRect(w-bw1-6, 0, 8, 8);
267       }
268       g.setColor(Color.black);
269       g.drawRect(w-bw1-6, 0, 8, 8);
270     }
271 */

272     // -----
273

274         g.setFont (NAME_FONT);
275         String JavaDoc name = c.getName();
276         if (name.length() == 0) {
277             name = "<missing>";
278             g.setColor(ERROR_COLOR);
279         } else {
280             g.setColor(Color.black);
281         }
282         drawString (g, name, itfWi, divH/2 - itfH/2 + INSETS, w - 2*itfWi, itfH, 0, true);
283
284
285         // ----- drawing interfaces
286

287         g.setFont(PROVIDED_FONT);
288         ((Graphics2D JavaDoc)g).setStroke(NORMAL_STROKE);
289         int h = divH + INSETS;
290         int hh = h + divH/2;
291         int hhh = hh - itfH/2;
292         int hhi = hh + itfH/2;
293
294         int ep = 2;
295
296         for (int i = 0; i < sItfList.size(); ++i) {
297             Interface itf = (Interface)sItfList.get(i);
298             if (sel == itf) {
299                 g.setColor(SELECTION_COLOR);
300                 g.fillRect(-1, hhh - 1, itfW + 1, itfH + 3);
301             } else if (c.isComposite() && expanded && sel == itf.getComplementaryInterface()) {
302                 g.setColor(SELECTION_COLOR);
303                 g.fillRect(bw1 + 1, hhh - 1, itfW + 1, itfH + 3);
304             }
305
306             g.setColor (itf.getStatus() == Interface.OK ? PROVIDED_COLOR : ERROR_COLOR);
307             if (mode == 0) name = itf.getName();
308       else if (mode == 1) name = itf.getSignature();
309       else name = " ";
310       name = ajustName (g, name, (w-2*bw1)/2);
311
312             if (isMasterCollectionItf(itf)) {
313                 if (expanded) {
314                     drawString (g, name, bw3+1, hhh + INSETS, w - 2*bw3, itfH, 0, true);
315                     g.drawLine(bw1, hh, bw2, hh);
316                     g.drawLine(bw2, hhh, bw2, hh + itfH/2);
317                     g.drawLine(bw2-2, hhh, bw2-2, hh + itfH/2);
318                 }
319             } else {
320                 if (c.isComposite() && expanded) {
321                     drawString (g, name, bw3+1, hhh + INSETS, w - 2*bw3, itfH, 0, true);
322                     g.drawLine(bw1, hh, bw2, hh);
323                     g.drawLine(bw2, hhh, bw2, hhi);
324                     g.drawLine(bw2-1, hhh, bw2-1, hhi);
325                 } else {
326           if (itf.isCollection()) {
327             g.setColor(Color.gray);
328             ep = 1;
329           }
330                     drawString
331             (g, name, itfW + INSETS, hhh + INSETS, w - 2*itfWi, itfH, 0, true);
332                 }
333                 g.drawLine(0, hh, itfW - 1, hh);
334                 g.drawLine(0, hhh, 0, hhi);
335                 g.drawLine(1, hhh, 1, hhi);
336             }
337             h += divH;
338             hh += divH;
339             hhh += divH;
340             hhi += divH;
341         }
342
343         g.setFont(REQUIRED_FONT);
344         h = divH + INSETS;
345         hh = h + divH/2;
346         hhh = hh - itfH/2;
347         hhi = hh + itfH/2;
348         for (int i = 0; i < cItfList.size(); ++i) {
349             Interface itf = (Interface)cItfList.get(i);
350             if (sel == itf) {
351                 g.setColor(SELECTION_COLOR);
352                 g.fillRect(w - itfW, hhh - 1, itfW+1, itfH+3);
353             } else if (c.isComposite() && expanded &&
354                  sel == itf.getComplementaryInterface())
355       {
356                 g.setColor(SELECTION_COLOR);
357                 g.fillRect(w - bw2 - 1, hhh - 1, itfW, itfH + 3);
358             }
359             g.setColor(itf.getStatus() == Interface.OK ? REQUIRED_COLOR : ERROR_COLOR);
360 // name = itf.getName();
361
if (mode == 0) name = itf.getName();
362       else if (mode == 1) name = itf.getSignature();
363       else name = " ";
364
365       name = ajustName (g, name, (w-2*bw1)/2);
366
367       Color JavaDoc col = g.getColor();
368       if (isMasterCollectionItf(itf)) {
369                 drawString
370           (g, name, itfW + INSETS, hhh + INSETS, w - 2*itfWi, itfH, 0, false);
371                 g.drawLine(w - itfW, hh, w - 1, hh);
372                 g.drawLine(w - 3, hhh, w - 3, hhi);
373                 g.drawLine(w, hhh, w, hhi);
374             } else {
375                 if (c.isComposite() && expanded) {
376                     drawString (g, name, bw3, hhh + INSETS, w - 2*bw3, itfH, 0, false);
377                     g.drawLine(w - bw2, hh, w - bw1 - 1, hh);
378                     g.drawLine(w - bw2, hhh, w - bw2, hhi);
379                 } else {
380           if (itf.isCollection()) {
381             g.setColor(Color.gray);
382             ep = 1;
383           }
384           drawString (g, name, itfWi, hhh + INSETS, w - 2*itfWi, itfH, 0, false);
385                 }
386                 g.drawLine(w - itfW, hh, w - 1, hh);
387                 g.drawLine(w - 1, hhh, w - 1, hhi);
388                 if (ep == 2) g.drawLine(w, hhh, w, hhi);
389             }
390       g.setColor (col);
391             h += divH;
392             hh += divH;
393             hhh += divH;
394             hhi += divH;
395         }
396         g.translate(-x, -y);
397     }
398
399   private String JavaDoc ajustName (Graphics JavaDoc g, String JavaDoc name, int max) {
400     FontMetrics JavaDoc fm = g.getFontMetrics();
401     int nameWidth = fm.stringWidth(name);
402     int paddWidth = fm.stringWidth(".. ");
403
404     if ((nameWidth > (max)) && (name.length()> 3)) {
405       while (nameWidth > (max-paddWidth)) {
406         int len = name.length(); if (len < 4) break;
407         name = name.substring(0, --len);
408         nameWidth = fm.stringWidth(name);
409       }
410       name = name+".. ";
411     }
412     return name;
413   }
414
415     public ComponentPart getComponentPart (
416     final Component c,
417     final Rectangle JavaDoc r,
418     final boolean expanded,
419     final int x0,
420     final int y0)
421     {
422         // eliminates trivial cases
423
if (x0 < r.x || x0 > r.x + r.width || y0 < r.y || y0 > r.y + r.height) {
424            return null;
425         }
426
427         // tests corners
428
initialize(c, r);
429         int part = isCorner(x + itfW, y, w - 2 * itfW, h, x0, y0);
430         if (part != -1) {
431            return new ComponentPart(c, null, part, r);
432         }
433
434         // tests interfaces
435
int h = divH + INSETS;
436         int hhh = h + divH/2 - itfH/2;
437         for (int i = 0; i < sItfList.size(); ++i) {
438             Interface itf = (Interface)sItfList.get(i);
439             if (isMasterCollectionItf(itf)) {
440                 if ((x0 >= x + bw1) && (x0 <= x + bw2) &&
441             (y0 >= y + hhh) && (y0 <= y + hhh + itfH))
442         {
443                     return new ComponentPart(
444             c, itf.getComplementaryInterface(), ComponentPart.INTERFACE, r);
445                 }
446             } else {
447                 if ((y0 >= y + hhh) && (y0 <= y + hhh + itfH)) {
448                     if (x0 <= x + itfW) {
449                         return new ComponentPart(c, itf, ComponentPart.INTERFACE, r);
450                     } else if ((x0 >= x + bw1) && (x0 <= x + bw2)) {
451                         if (c.isComposite() && expanded) {
452                             return new ComponentPart(
453                 c, itf.getComplementaryInterface(), ComponentPart.INTERFACE, r);
454                         }
455                     }
456                 }
457             }
458             h += divH;
459             hhh += divH;
460         }
461
462         h = divH + INSETS;
463         hhh = h + divH/2 - itfH/2;
464         for (int i = 0; i < cItfList.size(); ++i) {
465             Interface itf = (Interface)cItfList.get(i);
466             if (isMasterCollectionItf(itf)) {
467                 if ((x0 >= x + w - itfW) && (y0 >= y + hhh) && (y0 <= y + hhh + itfH)) {
468                     return new ComponentPart(c, itf, ComponentPart.INTERFACE, r);
469                 }
470             }
471             else if ((y0 >= y + hhh) && (y0 <= y + hhh + itfH)) {
472                 if (x0 >= x + w - itfW) {
473                     return new ComponentPart(c, itf, ComponentPart.INTERFACE, r);
474                 } else if ((x0 >= x + w - bw2) && (x0 <= x + w - bw1)) {
475                     if (c.isComposite() && expanded) {
476                         return new ComponentPart(
477               c, itf.getComplementaryInterface(), ComponentPart.INTERFACE, r);
478                     }
479                 }
480             }
481             h += divH;
482             hhh += divH;
483         }
484
485         // tests borders
486
part = isBorder (x+itfW, y, w-2*itfW, this.h, x0, y0);
487         if (part != -1) {
488             return new ComponentPart(c, null, part, r);
489         }
490         // tests header
491
if ((x0 >= x+itfW) && (x0 <= x+w-itfW) && (y0 >= y) && (y0 <= y+divH)) {
492             return new ComponentPart(c, null, ComponentPart.HEADER, r);
493         }
494         // tests content
495
if ((x0 >= x+itfW) && (x0 <= x+w-itfW) &&
496         (y0 >= y+divH) && (y0 <= y+this.h))
497     {
498             return new ComponentPart(c, null, ComponentPart.CONTENT, r);
499         }
500         return null;
501     }
502
503     public Point JavaDoc getInterfacePosition (
504     final Component c,
505     final Rectangle JavaDoc r,
506     final Interface i)
507     {
508         initialize(c, r);
509
510         int baseX = r.x + r.width;
511         int baseY = r.y + divH / 2 + INSETS;
512
513         if (!(i instanceof ClientInterface)) {
514             if (i.isInternal()) {
515                 int index = cItfList.indexOf(i.getComplementaryInterface());
516                 return new Point JavaDoc(baseX - bw2, baseY + divH*(index + 1));
517             } else {
518                 int index = sItfList.indexOf(i);
519                 return new Point JavaDoc(r.x, baseY + divH * (index + 1));
520             }
521         } else {
522             if (i.isInternal()) {
523                 int index = sItfList.indexOf(i.getComplementaryInterface());
524                 return new Point JavaDoc(r.x + bw2, baseY + divH*(index + 1));
525             } else {
526                 int index = cItfList.indexOf(i);
527                 return new Point JavaDoc(baseX, baseY + divH*(index + 1));
528             }
529         }
530     }
531
532     public Rectangle JavaDoc getSubComponentArea (final Component c, final Rectangle JavaDoc r) {
533         initialize(c, r);
534         int xp = x + INSETS + itfW + borderSize;
535         int yp = y + INSETS + borderSize;
536         int widthp = w - 2 * (INSETS + itfW + borderSize);
537         int heightp = h - 2 * (INSETS + borderSize);
538         return new Rectangle JavaDoc(xp, yp, widthp, heightp);
539     }
540
541   // -------------------------------------------------------------------------
542
// Other methods
543
// -------------------------------------------------------------------------
544

545   /**
546    * Prepares this component to draw the given component.
547    *
548    * @param c the component that will be drawn.
549    * @param r where the component will be drawn.
550    */

551
552     protected void initialize (final Component c, final Rectangle JavaDoc r) {
553         if (c == this.c && r == this.r) {
554            return;
555         }
556         this.c = c;
557         this.r = r;
558         x = r.x;
559         y = r.y;
560         w = r.width;
561         h = r.height;
562         sItfList = c.getServerInterfaces();
563         cItfList = c.getClientInterfaces();
564
565         int divisions = 2 + Math.max(sItfList.size(), cItfList.size());
566         divH = Math.min(MAX_DIV, (h - 2 * INSETS) / divisions);
567 // borderSize = divH;
568
borderSize = Math.min(5, (h - 2 * INSETS) / divisions);
569     itfH = (int)(divH * 0.75);
570         itfW = itfH / 2;
571         itfWi = itfW + INSETS;
572     bw1 = itfW + borderSize;
573         bw2 = 2*itfW + borderSize;
574         bw3 = 2*itfW + borderSize + INSETS;
575     }
576
577   /**
578    * Draws a string in the given rectangle.
579    *
580    * @param g the graphics to be used to draw the string.
581    * @param s the string to be drawn.
582    * @param x left border of the rectangle where s must be drawn.
583    * @param y top border of the rectangle where s must be drawn.
584    * @param dx w of the rectangle where s must be drawn.
585    * @param dy h of the rectangle where s must be drawn.
586    * @param insets horizontal insets to be removed from (x,y,dx,dy).
587    * @param left if the string must drawn left justified or right justified.
588    */

589
590     protected void drawString (
591     final Graphics JavaDoc g,
592     final String JavaDoc s,
593     final int x,
594     final int y,
595     final int dx,
596     final int dy,
597     final int insets,
598     final boolean left)
599     {
600     int size = dy - 2 * insets;
601         g.setFont(g.getFont().deriveFont((float)size));
602         FontMetrics JavaDoc fm = g.getFontMetrics();
603         double descent = ((double)fm.getDescent()) / fm.getHeight() * size;
604         int y0 = y + dy - insets - (int)Math.round(descent);
605         Shape JavaDoc shape = g.getClip();
606         g.clipRect(x, y, dx, dy);
607         if (left) {
608             g.drawString(s, x + insets, y0);
609         } else {
610             g.drawString(s, x + dx - insets - fm.stringWidth(s), y0);
611         }
612         g.setClip(shape);
613     }
614
615   /**
616    * Returns the corner of the given rectangle to which the given point
617    * corresponds.
618    *
619    * @param x left border of the rectangle.
620    * @param y top border of the rectangle.
621    * @param w w of the rectangle.
622    * @param h h of the rectangle.
623    * @param x0 x coordinate of the point.
624    * @param y0 y coordinate of the point.
625    * @return the type of the corner to which the given point corresponds, or -1
626    * if it does not corresponds to any corner.
627    */

628
629     protected int isCorner (
630     final int x,
631     final int y,
632     final int w,
633     final int h,
634     final int x0,
635     final int y0)
636   {
637         if (Math.abs(x0 - x) < EPS && Math.abs(y0 - y) < EPS) {
638             return ComponentPart.TOP_LEFT_CORNER;
639         }
640         if (Math.abs(x0 - (x + w)) < EPS && Math.abs(y0 - y) < EPS) {
641             return ComponentPart.TOP_RIGHT_CORNER;
642         }
643         if (Math.abs(x0 - x) < EPS && Math.abs(y0 - (y + h)) < EPS) {
644             return ComponentPart.BOTTOM_LEFT_CORNER;
645         }
646         if (Math.abs(x0 - (x + w)) < EPS && Math.abs(y0 - (y + h)) < EPS) {
647             return ComponentPart.BOTTOM_RIGHT_CORNER;
648         }
649         return -1;
650     }
651
652   /**
653    * Returns the border of the given rectangle to which the given point
654    * corresponds.
655    *
656    * @param x left border of the rectangle.
657    * @param y top border of the rectangle.
658    * @param w w of the rectangle.
659    * @param h h of the rectangle.
660    * @param x0 x coordinate of the point.
661    * @param y0 y coordinate of the point.
662    * @return the type of the border to which the given point corresponds, or -1
663    * if it does not corresponds to any border.
664    */

665
666     protected int isBorder (
667     final int x,
668     final int y,
669     final int w,
670     final int h,
671     final int x0,
672     final int y0)
673   {
674         if (Math.abs(x0 - x) < EPS && y0 >= y && y0 <= y + h) {
675             return ComponentPart.LEFT_BORDER;
676         }
677         if (Math.abs(y0 - y) < EPS && x0 >= x && x0 <= x + w) {
678             return ComponentPart.TOP_BORDER;
679         }
680         if (Math.abs(x0 - (x + w)) < EPS && y0 >= y && y0 <= y + h) {
681             return ComponentPart.RIGHT_BORDER;
682         }
683         if (Math.abs(y0 - (y + h)) < EPS && x0 >= x && x0 <= x + w) {
684             return ComponentPart.BOTTOM_BORDER;
685         }
686         return -1;
687     }
688
689   /**
690    * Returns <tt>true</tt> if the given interface is a master collection
691    * interface.
692    *
693    * @param itf a component interface.
694    * @return <tt>true</tt> if the given interface is a master collection
695    * interface.
696    */

697
698   private boolean isMasterCollectionItf (final Interface itf) {
699     return itf.isCollection() && itf.getMasterCollectionInterface() == null;
700   }
701 }
702
Popular Tags