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             @Override
     71             public void run() {
     72                 synchronized (PixelPerfectModel.this) {
     73                     PixelPerfectModel.this.mDevice = device;
     74                     PixelPerfectModel.this.mImage = image;
     75                     PixelPerfectModel.this.mViewNode = viewNode;
     76                     if (image != null) {
     77                         PixelPerfectModel.this.mCrosshairLocation =
     78                                 new Point(image.getBounds().width / 2, image.getBounds().height / 2);
     79                     } else {
     80                         PixelPerfectModel.this.mCrosshairLocation = null;
     81                     }
     82                     mOverlayImage = null;
     83                     PixelPerfectModel.this.mSelectedNode = null;
     84                     mZoom = DEFAULT_ZOOM;
     85                 }
     86             }
     87         });
     88         notifyImageLoaded();
     89         if (toDispose != null) {
     90             Display.getDefault().syncExec(new Runnable() {
     91                 @Override
     92                 public void run() {
     93                     toDispose.dispose();
     94                 }
     95             });
     96         }
     97         if (toDispose2 != null) {
     98             Display.getDefault().syncExec(new Runnable() {
     99                 @Override
    100                 public void run() {
    101                     toDispose2.dispose();
    102                 }
    103             });
    104         }
    105 
    106     }
    107 
    108     public void setCrosshairLocation(int x, int y) {
    109         synchronized (this) {
    110             mCrosshairLocation = new Point(x, y);
    111         }
    112         notifyCrosshairMoved();
    113     }
    114 
    115     public void setSelected(ViewNode selected) {
    116         synchronized (this) {
    117             this.mSelectedNode = selected;
    118         }
    119         notifySelectionChanged();
    120     }
    121 
    122     public void setTree(final ViewNode viewNode) {
    123         Display.getDefault().syncExec(new Runnable() {
    124             @Override
    125             public void run() {
    126                 synchronized (PixelPerfectModel.this) {
    127                     PixelPerfectModel.this.mViewNode = viewNode;
    128                     PixelPerfectModel.this.mSelectedNode = null;
    129                 }
    130             }
    131         });
    132         notifyTreeChanged();
    133     }
    134 
    135     public void setImage(final Image image) {
    136         final Image toDispose = this.mImage;
    137         Display.getDefault().syncExec(new Runnable() {
    138             @Override
    139             public void run() {
    140                 synchronized (PixelPerfectModel.this) {
    141                     PixelPerfectModel.this.mImage = image;
    142                 }
    143             }
    144         });
    145         notifyImageChanged();
    146         if (toDispose != null) {
    147             Display.getDefault().syncExec(new Runnable() {
    148                 @Override
    149                 public void run() {
    150                     toDispose.dispose();
    151                 }
    152             });
    153         }
    154     }
    155 
    156     public void setZoom(int newZoom) {
    157         synchronized (this) {
    158             if (newZoom < MIN_ZOOM) {
    159                 newZoom = MIN_ZOOM;
    160             }
    161             if (newZoom > MAX_ZOOM) {
    162                 newZoom = MAX_ZOOM;
    163             }
    164             mZoom = newZoom;
    165         }
    166         notifyZoomChanged();
    167     }
    168 
    169     public void setOverlayImage(final Image overlayImage) {
    170         final Image toDispose = this.mOverlayImage;
    171         Display.getDefault().syncExec(new Runnable() {
    172             @Override
    173             public void run() {
    174                 synchronized (PixelPerfectModel.this) {
    175                     PixelPerfectModel.this.mOverlayImage = overlayImage;
    176                 }
    177             }
    178         });
    179         notifyOverlayChanged();
    180         if (toDispose != null) {
    181             Display.getDefault().syncExec(new Runnable() {
    182                 @Override
    183                 public void run() {
    184                     toDispose.dispose();
    185                 }
    186             });
    187         }
    188     }
    189 
    190     public void setOverlayTransparency(double value) {
    191         synchronized (this) {
    192             value = Math.max(value, 0);
    193             value = Math.min(value, 1);
    194             mOverlayTransparency = value;
    195         }
    196         notifyOverlayTransparencyChanged();
    197     }
    198 
    199     public ViewNode getViewNode() {
    200         synchronized (this) {
    201             return mViewNode;
    202         }
    203     }
    204 
    205     public Point getCrosshairLocation() {
    206         synchronized (this) {
    207             return mCrosshairLocation;
    208         }
    209     }
    210 
    211     public Image getImage() {
    212         synchronized (this) {
    213             return mImage;
    214         }
    215     }
    216 
    217     public ViewNode getSelected() {
    218         synchronized (this) {
    219             return mSelectedNode;
    220         }
    221     }
    222 
    223     public IDevice getDevice() {
    224         synchronized (this) {
    225             return mDevice;
    226         }
    227     }
    228 
    229     public int getZoom() {
    230         synchronized (this) {
    231             return mZoom;
    232         }
    233     }
    234 
    235     public Image getOverlayImage() {
    236         synchronized (this) {
    237             return mOverlayImage;
    238         }
    239     }
    240 
    241     public double getOverlayTransparency() {
    242         synchronized (this) {
    243             return mOverlayTransparency;
    244         }
    245     }
    246 
    247     public static interface IImageChangeListener {
    248         public void imageLoaded();
    249 
    250         public void imageChanged();
    251 
    252         public void crosshairMoved();
    253 
    254         public void selectionChanged();
    255 
    256         public void treeChanged();
    257 
    258         public void zoomChanged();
    259 
    260         public void overlayChanged();
    261 
    262         public void overlayTransparencyChanged();
    263     }
    264 
    265     private IImageChangeListener[] getImageChangeListenerList() {
    266         IImageChangeListener[] listeners = null;
    267         synchronized (mImageChangeListeners) {
    268             if (mImageChangeListeners.size() == 0) {
    269                 return null;
    270             }
    271             listeners =
    272                     mImageChangeListeners.toArray(new IImageChangeListener[mImageChangeListeners
    273                             .size()]);
    274         }
    275         return listeners;
    276     }
    277 
    278     public void notifyImageLoaded() {
    279         IImageChangeListener[] listeners = getImageChangeListenerList();
    280         if (listeners != null) {
    281             for (int i = 0; i < listeners.length; i++) {
    282                 listeners[i].imageLoaded();
    283             }
    284         }
    285     }
    286 
    287     public void notifyImageChanged() {
    288         IImageChangeListener[] listeners = getImageChangeListenerList();
    289         if (listeners != null) {
    290             for (int i = 0; i < listeners.length; i++) {
    291                 listeners[i].imageChanged();
    292             }
    293         }
    294     }
    295 
    296     public void notifyCrosshairMoved() {
    297         IImageChangeListener[] listeners = getImageChangeListenerList();
    298         if (listeners != null) {
    299             for (int i = 0; i < listeners.length; i++) {
    300                 listeners[i].crosshairMoved();
    301             }
    302         }
    303     }
    304 
    305     public void notifySelectionChanged() {
    306         IImageChangeListener[] listeners = getImageChangeListenerList();
    307         if (listeners != null) {
    308             for (int i = 0; i < listeners.length; i++) {
    309                 listeners[i].selectionChanged();
    310             }
    311         }
    312     }
    313 
    314     public void notifyTreeChanged() {
    315         IImageChangeListener[] listeners = getImageChangeListenerList();
    316         if (listeners != null) {
    317             for (int i = 0; i < listeners.length; i++) {
    318                 listeners[i].treeChanged();
    319             }
    320         }
    321     }
    322 
    323     public void notifyZoomChanged() {
    324         IImageChangeListener[] listeners = getImageChangeListenerList();
    325         if (listeners != null) {
    326             for (int i = 0; i < listeners.length; i++) {
    327                 listeners[i].zoomChanged();
    328             }
    329         }
    330     }
    331 
    332     public void notifyOverlayChanged() {
    333         IImageChangeListener[] listeners = getImageChangeListenerList();
    334         if (listeners != null) {
    335             for (int i = 0; i < listeners.length; i++) {
    336                 listeners[i].overlayChanged();
    337             }
    338         }
    339     }
    340 
    341     public void notifyOverlayTransparencyChanged() {
    342         IImageChangeListener[] listeners = getImageChangeListenerList();
    343         if (listeners != null) {
    344             for (int i = 0; i < listeners.length; i++) {
    345                 listeners[i].overlayTransparencyChanged();
    346             }
    347         }
    348     }
    349 
    350     public void addImageChangeListener(IImageChangeListener listener) {
    351         synchronized (mImageChangeListeners) {
    352             mImageChangeListeners.add(listener);
    353         }
    354     }
    355 
    356     public void removeImageChangeListener(IImageChangeListener listener) {
    357         synchronized (mImageChangeListeners) {
    358             mImageChangeListeners.remove(listener);
    359         }
    360     }
    361 }
    362