2012.04.04

* LargeZoomObject was not working correctly if you started dragging the mark and
  then moved the mouse outside the widget (it wasn't setting and release mouse
  event capture properly).
* TileLayer now returns a Tile instance instead of a tile image URL. This allows
  implementing tiles that aren't just a single image. To replicate the old
  functionality, use the (now public) ImageTile class in the tiles subpackage.
* Since Google has been actively making it hard to support their maps, I have no
  choice to conclude that they don't want their maps to be used from libraries
  other than their own. Removed support for Google Maps.
* Updated code to compile cleanly under GWT 2.4, which is now required.


2011.04.04

* MapWidget's addOverlay and removeOverlay methods that took a
  Collection<Overlay> now take a Collection<? extends Overlay> arguments.
* Mobile AppleWebKit is now properly depected in all instances. Previously, it
  would not get properly detected when launching from the iPhone home screen.
* Removed the touch event related classes from GwtUtils as they are now
  available as part of GWT 2.2. As a consequence, SashaMaps now requires GWT 2.2
  or later.
* Removed TouchEventsCanceller, as you can now use EventCancellingPanel to
  cancel touch events, instead.
* The WidgetOverlay.makeXDraggable methods were renamed to explicitly specify
  whether the overlay is draggable by mouse or by touch. The new method names
  have a "ByMouse" or "ByTouch" suffix.
* The iOS demo now works properly in both portrait and landscape modes, and
  when switching between the two. This was done by adding "user-scalable=no" to
  the viewport meta tag in HTML (see updated documentation in the tutorial).
* The iPad is now fully supported! Previously the map worked, but would glitch
  and flicker when dragged/pinched due to a bug in Safari.
* Fixed the inertial drag action for touch devices. It was not calculating the
  speed and angle correctly. 
  


2010.04.16

* LatLng now has a fromUrlValue(String) method which is the inverse of
  LatLng.toUrlValue().
* Callback.callBack(T) has been renamed to Callback.callback(T) (lowercase 'b').
* Added TouchEventsCanceller, a new TouchListener which invokes
  cancelBubble(true) and preventDefault() on all events it receives. This is
  useful to completely prevent the default responses to touch gestures on the
  iPhone.
* Fixed DragRecognizer to properly cancel dragging when a 2nd finger touches
  the screen.
* Fixed PinchRecognizer to be more lenient when detecting pinching. It now
  allows the first finger to move before the 2nd finger touches the screen.
* The MapWidget is no longer itself keyboard-focusable.
* com.maryanovsky.gwtutils.ui.EventCancellingPanel, a new class, has been added
  to GwtUtils to facilitate convenient cancelling of event bubbling and the
  prevention of default action. To cancel touch events, use
  com.maryanovsky.gwtutils.client.iphone.ui.event.touch.TouchCanceller.
* GwtUtils and SashaMaps have been updated to use the new GWT 1.6 EventHandler
  system. The following has changed: 
  - ImageButton.onClick() has been removed. Instead of overriding it, simply add
    a click handler.
  - ImageButton.addClickListener() and ImageButton.removeClickListener() have
    been removed. Use ImageButton.addClickHandler() instead.
  - Form.setDefaultFocusedWidget now takes a Focusable as argument.
  - UiUtils.trackResizes has been renamed to addSizeChangeHandler.
    UiUtils.stopTrackingResizes has been removed. Instead, you simply use the
    HandlerRegistration returned by addSizeChangeHandler.
* Added support for the new ClientBundle:
  - ImageButton now has constructors which take ImageResource arguments.
  - LargeZoomWidget.Images is now a ClientBundle.
  - BubbleWidget.Images is now a ClientBundle.
  - ScaleWidget.Images is now a ClientBundle.
* The com.maryanovsky.gwtutils.client.iphone package has been completely
  reworked to use the new event handling system.
* All of the classes and packages in com.maryanovsky.gwtutils.client.iphone
  have been moved into the iphone.ui subpackage, to make room for future
  iphone-related, but not UI-related classes/packages.
* UserEventManager and the corresponding Actions are gone. Instead, a mechanism
  similar to iPhone gesture recognitions has been implemented. See the
  com.maryanovsky.gwtutils.client.ui.mouse.gestures package for more
  information.
* IPhoneStandardActions and DesktopStandardActions methods now return the
  gesture recognizers for the gestures they add a action for. The method names
  have been renamed accordingly.
* All the map actions are now implemented in their own top-level classes under
  the actions.desktop and actions.iphone subpackages of the
  com.maryanovsky.map.client package. IPhoneStandardActions and
  DesktopStandardActions have been moved to their respective package.
* Added ButtonTapRecognizer and corresponding classes in the
  iphone.ui.touch.gestures.buttontap subpackage. This recognizes a tap on a
  button, which is different from a regular one (for example, it allows the
  finger to move before lifting).
* All the gesture recognizers (for both mouse and touch events) now take a
  Condition argument which allows creating recognizers for a subset of the
  gestures normally recognized. For example, a TapRecognizer may be customized
  to only recognize double-taps.




2009.09.24

* Added MapWidget.setLoadTilesDuringTemporaryChanges(boolean), a new method
  which allows disabling the loading of new tiles during temporary changes to
  the map's location (such as while the user is in the middle of panning the
  map). This speeds up things on slower devices, such as an iPhone. Note that
  the default value of this setting is false when running on Mobile Safari.
* Added new methods to control the magnification of the map in MapWidget:
  setMagnification, getMagnification and applyMagnification.
* Added a new method: MapWidget.getUserEventWidget().
* TileLayerWidget.isMagnificationSupported() and
  MapWidget.isAnimatedZoomSupported() are now deprecated and always return true.
* MapWidget.startAnimation() now takes a MapAnimation as argument instead of a
  regular Animation. The new MapWidget.MapAnimation class is a subclass of
  Animation that adds methods for getting notified before temporary offset or
  magnification are set on the map widget. If you've previously used custom
  animations with MapWidget, simply subclass MapWidget.MapAnimation instead of
  Animation to correct compilation errors.
* UiUtils.setVisible(Widget, boolean) was renamed to setVisibility.
* Added a new method, UiUtils.getVisibility(Widget).
* Added a new method, MapWidget.getOverlays().
* MapWidget now works (properly) on the iPhone!
* WidgetOverlay now works properly on the iPhone, including dragging.
* ImageButton now works properly on the iPhone. 
* Removed ImageButton.handleBrowserEvent(Event). You may still listen to click
  events in a subclass by overriding the new ImageButton.onClick() method.
* The abstract map action classes (MapClickAction, MapDragAction, MapMoveAction
  and MapWheelAction) classes that were previously member types of MapWidget
  have been made into top-level classes and moved to the new actions subpackage.
* The map action implementations (MapWidget.DRAG_MAP_ACTION,
  MapWidget.PAN_ACTION etc.) have been moved to the new DesktopStandardActions
  class in the new actions subpackage. 
* AreaSelectionAction has been moved to the new actions subpackage.



2009.07.24

* The com.maryanovsky.gwtutils.client package has been refactored into several
  subpackages: event, geom, net, text and ui.
* Added Properties, a new class, to GwtUtils. A Properties object holds a set of
  property names mapped to values, which can be retrieved and parsed as several
  types (integer, double etc.).
* Added a parseProperties(propertiesText, boolean trim) method to ParseUtils,
  which optionally trims the property names and values.
* Added a getUrlParams(Map<String, String> params) method to Utils, which adds
  the URL parameters of the current page to the specified map.
* Added Application, a new class, to GwtUtils. The Application class implements
  EntryPoint and handles much of the work required to start an application (such
  as retrieving the settings).
* Added Factory, a new interface, to GwtUtils.
* Added LatLngBounds, a new class, to SashaMaps. Also, added two new related
  methods to MapWidget: getBounds() which returns the LatLngBounds of the
  current display and show(LatLngBounds bounds, boolean animate) which displays
  the specified bounds with optional animation.
* Fixed a bug in WidgetOverlay which caused overlays that were removed and then
  re-added not to be positioned properly (they were losing their
  "position:absolute" CSS attribute when removed).
* Added a new method: WidgetOverlay.updateWidgetSize(SizeView), which should be
  invoked when the size of the widget changes, so that WidgetOverlay can update
  its position accordingly.
* Added BubbleWidget, a new map widget/overlay to SashaMaps. BubbleWidget is a
  comics-style "talk" bubble which can display arbitrary content. The class can
  be found in the com.maryanovsky.map.client.widgets.bubble package.
* Utils.getUrlParams(Map<String, String>) is now implemented using
  Window.Location.getParameterMap() instead of native code directly.
  Additionally, it now returns the map, after adding the parameters to it.
* Added a new method, Utils.getUrlParams(), which returns the map of URL
  parameters.
* Added key modifier masks to UserEventManager and a getModifiers(Event) method
  which returns an OR of the modifiers pressed for the event.
* All the action setter methods in UserEventManager now allow specifying which
  keyboard modifiers must be pressed for the action to be invoked. The old
  action setter methods which take no argument will now register the action to
  be called only when no keyboard modifiers are pressed (note that previously it
  would invoke it regardless of which modifiers are pressed, so this change
  could break the behaviour of some apps).
* Added two new convenience methods to UiUtils:
  setAbsoluteBounds(Widget, RectangleView) and setBounds(Widget, RectangleView).
* Added AreaSelectionAction, a new map action which allows the user to select
  the area he wants to zoom-in on by dragging a selection rectangle.
* Animated zoom is now supported under all browsers and platforms. Note,
  however, that on some browser/OS combinations the animation is not as smooth
  as on others, so you may want to disable animated zoom on those. In
  particular, Firefox under Windows seems to suffer from this problem.
* Fixed a bug in UserEventManager which sometimes caused mouse wheel up/down
  events to go unreported.
* Added 3 new interfaces to com.maryanovsky.gwtutils.client.text: Encoder,
  Decoder and Transcoder. Transcoder also contains implementations for some
  common data types.
* Added 3 new methods to BrowserUtils: getHostname(), getPathname() and
  setDocumentLocation(String).
* Added a new interface to com.maryanovsky.gwtutils.client.event: HasChange.
* Added a new class to com.maryanovsky.gwtutils.client.ui: PlainHyperlink.
* ParseUtils.parseProperties now allows continuing the logical line on a new
  physical line by ending it with a backslash.
* Fixed a bug which sometimes caused magnified tiles (during animated zoom) to
  be placed wrongly, breaking the lovely effect.
* Added new methods to BrowserUtils to detect some common operating systems:
  isWindows(), isMacOS() and isLinux().



2009.05.21

* GwtUtils and SashaMaps have been updated to use the new language features
  available in Java 1.5, the support for which was added in GWT 1.5. This
  includes use of type-parameterization, foreach loops, better use of
  Collections etc. This change affects users of SashaMaps in ways listed below.
* GWT 1.5.3 is now required to compile SashaMaps.
* Alignment is now an enum. It no longer has a public constructor, but instead
  a getInstance(HorizontalAlignmentConstant, VerticalAlignmentConstant) method.
* Callback is now parameterized with the type of the object passed to the
  callback method.
* Pair is now type-parameterized, in the obvious manner.
* ReadyListener and DelegatingReadyListenerCollection are now parameterized with
  the type of the source object.
* GroupReadyListener is now parameterized with both the type of the items in the
  interest set and the type of the source object.
* GroupReadyListener's constructor no longer allows a null value for the source
  parameter. This is because the type of the source parameter must be known at
  compile time. Previously, a null value meant that the newly created
  GroupReadyListener itself was used as the source.
* ResultCallback is now parameterized with the type of the result object.
* XmlResponseHandler is now parameterized with the type of the result object.
* An XmlResponseHandler with a null parser must either be parameterized with
  com.google.gwt.xml.client.Document or override the parseResponse(Document)
  method.
* The XmlResponseHandler constructor that does not take a parser as an argument
  has been removed as it can only be used if the result object is of type
  Document.
* The setGridRow, addWidget and addDialogButtons methods in UiUtils now take
  Lists of widgets and vertical and horizontal alignments. Previously they took
  arrays.
* Wherever the documentation of a method asked to treat the returned collection
  as unmodifiable (and in many places where it forgot to do so, but obviously
  intended to), the returned collection is now actually unmodifiable.
* MenuItemSeparator has been removed from GwtUtils, as GWT 1.5 has this
  functionality built-in.
* Updated the GoogleMaps implementation to use the new tile protocol (Google
  stopped supporting the old one).



2008.11.07

* Moved support for Google Maps into its own package -
  com.maryanovsky.map.client.google. The com.maryanovsky.map.client.impl package
  is no longer with us.
* Using Google Maps now requires a Google Maps API key.
* Added a ParseUtils class into GwtUtils. The class has some useful parsing
  utilities, mainly for processing XML documents.
* Many classes, which were not meant to be subclassed, are now declared final.
* LatLng now allows -180 as a legal longitude value.
* LatLng.equals(Object) and LatLng.hashCode() now compare LatLng objects for
  geographical identity. That is, two LatLng objects are considered equal if
  they represent the same location on the globe. For example,
  (latitude=20, longitude=-180) and (latitude=20, longitude=180) are equal.
* Added a new interface, DoublePointView, and an implementation, DoublePoint, to
  GwtUtils. Additionally, LatLng now implements DoublePointView.
* Fixed a bug in TileLayerWidget where tile width and tile height were mixed up,
  which would have caused problems for tile layers where they are different.
* The location passed to TileLayer.getTileUrl(x,y,zoom) is now the middle of the
  tile instead of the top-left. This is done to avoid tile-boundary issues and
  make it easier on TileLayer implementations to return the right tile. Existing
  correct TileLayer implementations should not be affected.
* Added support for Web Map Service maps - see the
  com.maryanovsky.map.client.opengis.wms package.
* Refactored the way projections are implemented - see the new
  com.maryanovsky.map.client.projections package and the AbstractProjection
  class.
* Replaced WidgetOverlay's 4 getters and setters of horizontal and vertical
  alignment with setAlignment(Alignment) and getAlignment().
* Improved the performance of adding many WidgetOverlays and the handling of the
  map when many have been added.
* The styling of the rectangle in the overview map widget marking the bounds of
  the main map widget is no longer hard-coded. It now sits in the overview.css
  file and can be overridden.


2008.07.28

* OverviewMapWidget.Synchronization has a new method:
  MapLocationModel createOverviewLocationModel(MapWidget mainWidget). This
  method is responsible for creating the MapLocationModel of the overview map
  widget. Assigning this responsibility to a separate method allows the
  overview MapLocationModel to be different from the model of the main map
  widget. Previously, the overview map widget used a copy of main map widget's
  model, which, for example, restricted it to the same range of zooms. The
  default implementation of the new method in
  OverviewMapWidget.StandardSynchronization now behaves as OverviewMapWidget
  used to (i.e. creates a copy of the main map widget's model).
* Moved OverviewMapWidget into com.maryanovsky.map.client.widgets.overview.
  Future map related widgets will also be placed under the widgets subpackage.
* Implemented a GoogleMaps-like LargeZoomWidget.
* Implemented a GoogleMaps-like ScaleWidget.
* Added a new method to the Projection interface - getWrapSize(int zoom), which
  returns the size of the entire map in pixels at a given zoom. This allows
  MapWidget to correctly wrap locations when the entire map (earth) is displayed
  more than once. 
* The length of pan and zoom animations in MapWidget is now customizeable.
* Changed the default length of pan and zoom animations in MapWidget from 500ms
  to 300ms.
* Fixed a bug in PilePanel (a GwtUtils class) causing PopupPanels to appear
  behind any overlays and widgets on the map.
* To improve performance, WidgetOverlay now hides (via setVisible(false)) its
  widget if the widget's bounds do not intersect with the bounds of the overlay
  panel.
* Many changes and new features in the GwtUtils library.
* Other bugfixes I implemented but didn't write down their descriptions.
* The release file now includes the tutorial and the javadoc for both Sasha Maps
  and GwtUtils.
* The released source is now obfuscated. You may receive the full unobfuscated
  source by obtaining a commercial license. 
