Home | History | Annotate | Download | only in models
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.hierarchyviewerlib.models;
     18 
     19 import com.android.ddmlib.IDevice;
     20 import com.android.hierarchyviewerlib.device.ViewNode;
     21 
     22 import org.eclipse.swt.graphics.Image;
     23 import org.eclipse.swt.graphics.Point;
     24 import org.eclipse.swt.widgets.Display;
     25 
     26 import java.util.ArrayList;
     27 
     28 public class PixelPerfectModel {
     29 
     30     public static final int MIN_ZOOM = 2;
     31 
     32     public static final int MAX_ZOOM = 24;
     33 
     34     public static final int DEFAULT_ZOOM = 8;
     35 
     36     public static final int DEFAULT_OVERLAY_TRANSPARENCY_PERCENTAGE = 50;
     37 
     38     private IDevice mDevice;
     39 
     40     private Image mImage;
     41 
     42     private Point mCrosshairLocation;
     43 
     44     private ViewNode mViewNode;
     45 
     46     private ViewNode mSelectedNode;
     47 
     48     private int mZoom;
     49 
     50     private final ArrayList<IImageChangeListener> mImageChangeListeners =
     51             new ArrayList<IImageChangeListener>();
     52 
     53     private Image mOverlayImage;
     54 
     55     private double mOverlayTransparency = DEFAULT_OVERLAY_TRANSPARENCY_PERCENTAGE / 100.0;
     56 
     57     private static PixelPerfectModel sModel;
     58 
     59     public static PixelPerfectModel getModel() {
     60         if (sModel == null) {
     61             sModel = new PixelPerfectModel();
     62         }
     63         return sModel;
     64     }
     65 
     66     public void setData(final IDevice device, final Image image, final ViewNode viewNode) {
     67         final Image toDispose = this.mImage;
     68         final Image toDispose2 = this.mOverlayImage;
     69         Display.getDefault().syncExec(new Runnable() {
     70             public void run() {
     71                 synchronized (PixelPerfectModel.this) {
     72                     PixelPerfectModel.this.mDevice = device;
     73                     PixelPerfectModel.this.mImage = image;
     74                     PixelPerfectModel.this.mViewNode = viewNode;
     75                     if (image != null) {
     76                         PixelPerfectModel.this.mCrosshairLocation =
     77                                 new Point(image.getBounds().width / 2, image.getBounds().height / 2);
     78                     } else {
     79                         PixelPerfectModel.this.mCrosshairLocation = null;
     80                     }
     81                     mOverlayImage = null;
     82                     PixelPerfectModel.this.mSelectedNode = null;
     83                     mZoom = DEFAULT_ZOOM;
     84                 }
     85             }
     86         });
     87         notifyImageLoaded();
     88         if (toDispose != null) {
     89             Display.getDefault().syncExec(new Runnable() {
     90                 public void run() {
     91                     toDispose.dispose();
     92                 }
     93             });
     94         }
     95         if (toDispose2 != null) {
     96             Display.getDefault().syncExec(new Runnable() {
     97                 public void run() {
     98                     toDispose2.dispose();
     99                 }
    100             });
    101         }
    102 
    103     }
    104 
    105     public void setCrosshairLocation(int x, int y) {
    106         synchronized (this) {
    107             mCrosshairLocation = new Point(x, y);
    108         }
    109         notifyCrosshairMoved();
    110     }
    111 
    112     public void setSelected(ViewNode selected) {
    113         synchronized (this) {
    114             this.mSelectedNode = selected;
    115         }
    116         notifySelectionChanged();
    117     }
    118 
    119     public void setTree(final ViewNode viewNode) {
    120         Display.getDefault().syncExec(new Runnable() {
    121             public void run() {
    122                 synchronized (PixelPerfectModel.this) {
    123                     PixelPerfectModel.this.mViewNode = viewNode;
    124                     PixelPerfectModel.this.mSelectedNode = null;
    125                 }
    126             }
    127         });
    128         notifyTreeChanged();
    129     }
    130 
    131     public void setImage(final Image image) {
    132         final Image toDispose = this.mImage;
    133         Display.getDefault().syncExec(new Runnable() {
    134             public void run() {
    135                 synchronized (PixelPerfectModel.this) {
    136                     PixelPerfectModel.this.mImage = image;
    137                 }
    138             }
    139         });
    140         notifyImageChanged();
    141         if (toDispose != null) {
    142             Display.getDefault().syncExec(new Runnable() {
    143                 public void run() {
    144                     toDispose.dispose();
    145                 }
    146             });
    147         }
    148     }
    149 
    150     public void setZoom(int newZoom) {
    151         synchronized (this) {
    152             if (newZoom < MIN_ZOOM) {
    153                 newZoom = MIN_ZOOM;
    154             }
    155             if (newZoom > MAX_ZOOM) {
    156                 newZoom = MAX_ZOOM;
    157             }
    158             mZoom = newZoom;
    159         }
    160         notifyZoomChanged();
    161     }
    162 
    163     public void setOverlayImage(final Image overlayImage) {
    164         final Image toDispose = this.mOverlayImage;
    165         Display.getDefault().syncExec(new Runnable() {
    166             public void run() {
    167                 synchronized (PixelPerfectModel.this) {
    168                     PixelPerfectModel.this.mOverlayImage = overlayImage;
    169                 }
    170             }
    171         });
    172         notifyOverlayChanged();
    173         if (toDispose != null) {
    174             Display.getDefault().syncExec(new Runnable() {
    175                 public void run() {
    176                     toDispose.dispose();
    177                 }
    178             });
    179         }
    180     }
    181 
    182     public void setOverlayTransparency(double value) {
    183         synchronized (this) {
    184             value = Math.max(value, 0);
    185             value = Math.min(value, 1);
    186             mOverlayTransparency = value;
    187         }
    188         notifyOverlayTransparencyChanged();
    189     }
    190 
    191     public ViewNode getViewNode() {
    192         synchronized (this) {
    193             return mViewNode;
    194         }
    195     }
    196 
    197     public Point getCrosshairLocation() {
    198         synchronized (this) {
    199             return mCrosshairLocation;
    200         }
    201     }
    202 
    203     public Image getImage() {
    204         synchronized (this) {
    205             return mImage;
    206         }
    207     }
    208 
    209     public ViewNode getSelected() {
    210         synchronized (this) {
    211             return mSelectedNode;
    212         }
    213     }
    214 
    215     public IDevice getDevice() {
    216         synchronized (this) {
    217             return mDevice;
    218         }
    219     }
    220 
    221     public int getZoom() {
    222         synchronized (this) {
    223             return mZoom;
    224         }
    225     }
    226 
    227     public Image getOverlayImage() {
    228         synchronized (this) {
    229             return mOverlayImage;
    230         }
    231     }
    232 
    233     public double getOverlayTransparency() {
    234         synchronized (this) {
    235             return mOverlayTransparency;
    236         }
    237     }
    238 
    239     public static interface IImageChangeListener {
    240         public void imageLoaded();
    241 
    242         public void imageChanged();
    243 
    244         public void crosshairMoved();
    245 
    246         public void selectionChanged();
    247 
    248         public void treeChanged();
    249 
    250         public void zoomChanged();
    251 
    252         public void overlayChanged();
    253 
    254         public void overlayTransparencyChanged();
    255     }
    256 
    257     private IImageChangeListener[] getImageChangeListenerList() {
    258         IImageChangeListener[] listeners = null;
    259         synchronized (mImageChangeListeners) {
    260             if (mImageChangeListeners.size() == 0) {
    261                 return null;
    262             }
    263             listeners =
    264                     mImageChangeListeners.toArray(new IImageChangeListener[mImageChangeListeners
    265                             .size()]);
    266         }
    267         return listeners;
    268     }
    269 
    270     public void notifyImageLoaded() {
    271         IImageChangeListener[] listeners = getImageChangeListenerList();
    272         if (listeners != null) {
    273             for (int i = 0; i < listeners.length; i++) {
    274                 listeners[i].imageLoaded();
    275             }
    276         }
    277     }
    278 
    279     public void notifyImageChanged() {
    280         IImageChangeListener[] listeners = getImageChangeListenerList();
    281         if (listeners != null) {
    282             for (int i = 0; i < listeners.length; i++) {
    283                 listeners[i].imageChanged();
    284             }
    285         }
    286     }
    287 
    288     public void notifyCrosshairMoved() {
    289         IImageChangeListener[] listeners = getImageChangeListenerList();
    290         if (listeners != null) {
    291             for (int i = 0; i < listeners.length; i++) {
    292                 listeners[i].crosshairMoved();
    293             }
    294         }
    295     }
    296 
    297     public void notifySelectionChanged() {
    298         IImageChangeListener[] listeners = getImageChangeListenerList();
    299         if (listeners != null) {
    300             for (int i = 0; i < listeners.length; i++) {
    301                 listeners[i].selectionChanged();
    302             }
    303         }
    304     }
    305 
    306     public void notifyTreeChanged() {
    307         IImageChangeListener[] listeners = getImageChangeListenerList();
    308         if (listeners != null) {
    309             for (int i = 0; i < listeners.length; i++) {
    310                 listeners[i].treeChanged();
    311             }
    312         }
    313     }
    314 
    315     public void notifyZoomChanged() {
    316         IImageChangeListener[] listeners = getImageChangeListenerList();
    317         if (listeners != null) {
    318             for (int i = 0; i < listeners.length; i++) {
    319                 listeners[i].zoomChanged();
    320             }
    321         }
    322     }
    323 
    324     public void notifyOverlayChanged() {
    325         IImageChangeListener[] listeners = getImageChangeListenerList();
    326         if (listeners != null) {
    327             for (int i = 0; i < listeners.length; i++) {
    328                 listeners[i].overlayChanged();
    329             }
    330         }
    331     }
    332 
    333     public void notifyOverlayTransparencyChanged() {
    334         IImageChangeListener[] listeners = getImageChangeListenerList();
    335         if (listeners != null) {
    336             for (int i = 0; i < listeners.length; i++) {
    337                 listeners[i].overlayTransparencyChanged();
    338             }
    339         }
    340     }
    341 
    342     public void addImageChangeListener(IImageChangeListener listener) {
    343         synchronized (mImageChangeListeners) {
    344             mImageChangeListeners.add(listener);
    345         }
    346     }
    347 
    348     public void removeImageChangeListener(IImageChangeListener listener) {
    349         synchronized (mImageChangeListeners) {
    350             mImageChangeListeners.remove(listener);
    351         }
    352     }
    353 }
    354