001 package edu.nrao.sss.model.source.experiment; 002 003 import java.awt.Dimension; 004 import java.awt.Graphics; 005 import java.awt.Graphics2D; 006 import java.util.Collection; 007 008 import javax.swing.JComponent; 009 import javax.swing.ProgressMonitor; 010 import javax.swing.SwingWorker; 011 012 import edu.nrao.sss.model.source.Source; 013 014 /** 015 * A component that shows the location of sources relative to a central 016 * position. 017 * <p> 018 * This map allows users to move the center of the map by clicking on 019 * a location that becomes the new center. It also allows the user 020 * to zoom in or out by using a mouse wheel. This map pops up 021 * information about a source when it is right-clicked.</p> 022 * <p> 023 * <i>This class is a stubbed prototype. It's API needs many additions 024 * before it is ready for production.</i></p> 025 * <p> 026 * <b><u><span style="font-variant:small-caps">Mouse Actions</span></u></b> 027 * <dl> 028 * <dt>Single Left Click</dt> 029 * <dd>Causes the point under the mouse pointer to become the new 030 * center of the map.</dd> 031 * <br/> 032 * <dt>Single Right Click</dt> 033 * <dd>Pops up information about the source under the mouse pointer. 034 * <i>(At this time a window pops up no matter where the mouse 035 * pointer is, and it contains a temporary fixed message.)</i></dd> 036 * <br/> 037 * <dt>Mouse Wheel Movement</dt> 038 * <dl> 039 * <dt><i>While pressing neither <tt>shift</tt> key nor <tt>control</tt> key:</i></dt> 040 * <dd>Zooms the map in or out while maintaining the same center.</dd> 041 * <dt><i>While pressing <tt>shift</tt> key, but not <tt>control</tt> key:</i></dt> 042 * <dd>Changes the latitude of the center of the map, without changing 043 * either the longitude or the radius.</dd> 044 * <dt><i>While pressing <tt>control</tt> key, but not <tt>shift</tt> key:</i></dt> 045 * <dd>Changes the longitude of the center of the map, without changing 046 * either the latitude or the radius.</d> 047 * <dt><i>While pressing both <tt>shift</tt> key and <tt>control</tt> key:</i></dt> 048 * <dd>Changes both the longitude and latitude of the center of the map, 049 * without changing the radius.</dd> 050 * </dl> 051 * </dl> 052 * <p> 053 * <b>Version Info:</b> 054 * <table style="margin-left:2em"> 055 * <tr><td>$Revision: 1710 $</td></tr> 056 * <tr><td>$Date: 2008-11-14 11:54:07 -0700 (Fri, 14 Nov 2008) $</td></tr> 057 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 058 * </table></p> 059 * 060 * @author David M. Harland 061 * @since 2007-06-07 062 */ 063 public class SourceMapComponent 064 extends JComponent 065 { 066 private static final long serialVersionUID = 1L; 067 068 protected SourceMap map; 069 070 //============================================================================ 071 // 072 //============================================================================ 073 074 /** Creates a new instance. */ 075 public SourceMapComponent() 076 { 077 map = new SourceMap(); 078 079 configure(); 080 } 081 082 /** Initializes UI properties at time of construction. */ 083 private void configure() 084 { 085 setDoubleBuffered(true); 086 087 Dimension prefSize = new Dimension(map.getWidth(), map.getHeight()); 088 setPreferredSize(prefSize); 089 setSize(prefSize); 090 091 new SourceMapMouseControl(this); //Calls back to this.addMouseXxxListener 092 } 093 094 //============================================================================ 095 // PAINTING 096 //============================================================================ 097 098 @Override 099 public void paintComponent(Graphics g) 100 { 101 Graphics2D g2 = (Graphics2D)g; 102 103 super.paintComponent(g2); 104 105 map.setSize(this.getSize()); 106 107 map.paint(g2); 108 } 109 110 /** 111 * Allows the time consuming task of adding lots of new sources to 112 * be performed in a thread other than the event dispatch thread. 113 */ 114 private class AddSourceTask 115 extends SwingWorker<Void, Void> 116 { 117 private SourceMapComponent owner; 118 private Collection<? extends Source> newSources; 119 private String collectionName; 120 121 public AddSourceTask(SourceMapComponent owner) 122 { 123 this.owner = owner; 124 collectionName = null; 125 } 126 127 private ProgressMonitor monitor; 128 129 void setRawMaterial(Collection<? extends Source> newSources) 130 { 131 this.newSources = newSources; 132 } 133 134 void setCollectionName(String newName) 135 { 136 collectionName = (newName == null) ? "Anonymous" : newName; 137 } 138 139 public Void doInBackground() 140 { 141 int srcCnt = newSources.size(); 142 143 monitor = 144 new ProgressMonitor(owner, "Adding " + srcCnt + " New Sources to Map", 145 "Added 0 sources so far...", 0, newSources.size()); 146 147 int displayIncr = 10; 148 149 if (srcCnt >= 1000) 150 { 151 displayIncr = 100; 152 monitor.setMillisToDecideToPopup(0); 153 monitor.setMillisToPopup(0); 154 } 155 else if (srcCnt <= 20) 156 { 157 displayIncr = 1; 158 } 159 160 int s=0; 161 for (Source src : newSources) 162 { 163 owner.map.addSource(src, collectionName); 164 165 monitor.setProgress(++s); 166 167 if (s % displayIncr == 0) 168 monitor.setNote("Added " + s + " sources so far..."); 169 } 170 171 monitor.close(); 172 173 return null; 174 } 175 176 @Override 177 public void done() 178 { 179 owner.repaint(); 180 } 181 } //end class AddSourceTask 182 183 //============================================================================ 184 // WRAPPING SourceMap 185 //============================================================================ 186 187 /** 188 * @param newSource 189 */ 190 public void addSource(Source newSource) 191 { 192 map.addSource(newSource); 193 } 194 195 /** 196 * @param newSources 197 */ 198 public void addSources(Collection<? extends Source> newSources) 199 { 200 addSources(newSources, null); 201 } 202 203 /** 204 * @param newSource 205 * @param collectionName 206 */ 207 public void addSource(Source newSource, String collectionName) 208 { 209 map.addSource(newSource, collectionName); 210 } 211 212 /** 213 * @param newSources 214 * @param collectionName 215 */ 216 public void addSources(Collection<? extends Source> newSources, 217 String collectionName) 218 { 219 //A SwingWorker that does the time consuming task of adding sources to 220 //this map in a separate thread. 221 AddSourceTask sourceAdder = new AddSourceTask(this); 222 223 sourceAdder.setCollectionName(collectionName); 224 sourceAdder.setRawMaterial(newSources); 225 sourceAdder.execute(); 226 } 227 228 //============================================================================ 229 // 230 //============================================================================ 231 232 public StringBuilder appendHtmlMouseHelp(StringBuilder dest) 233 { 234 if (dest == null) 235 dest = new StringBuilder(); 236 237 //TODO This text s/b in an external store of some kind 238 239 dest.append("<dl>"); 240 dest.append("<dt><b>Single Left Click</b></dt>"); 241 dest.append("<dd>Causes the point under the mouse pointer to become the new"); 242 dest.append(" center of the map.</dd>"); 243 dest.append("<dt><br/><b>Single Right Click</b></dt>"); 244 dest.append("<dd>Pops up information about the source under the mouse pointer."); 245 dest.append(" <i>(At this time a window pops up no matter where the mouse"); 246 dest.append(" pointer is, and it contains a temporary fixed message.)</i></dd>"); 247 dest.append("<dt><br/><b>Mouse Wheel Movement</b></dt>"); 248 dest.append("<dl>"); 249 dest.append("<dt><i>While pressing neither <tt>shift</tt> key nor <tt>control</tt> key:</i></dt>"); 250 dest.append("<dd>Zooms the map in or out while maintaining the same center.</dd>"); 251 dest.append("<dt><i>While pressing <tt>shift</tt> key, but not <tt>control</tt> key:</i></dt>"); 252 dest.append("<dd>Changes the latitude of the center of the map, without changing"); 253 dest.append(" either the longitude or the radius.</dd>"); 254 dest.append("<dt><i>While pressing <tt>control</tt> key, but not <tt>shift</tt> key:</i></dt>"); 255 dest.append("<dd>Changes the longitude of the center of the map, without changing"); 256 dest.append(" either the latitude or the radius.</dd>"); 257 dest.append("<dt><i>While pressing both <tt>shift</tt> key and <tt>control</tt> key:</i></dt>"); 258 dest.append("<dd>Changes both the longitude and latitude of the center of the map,"); 259 dest.append(" without changing the radius.</dd>"); 260 dest.append("</dl>"); 261 dest.append("</dl>"); 262 263 264 return dest; 265 } 266 }