// Copyright (C) 2013 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.gerrit.client; import com.google.gerrit.client.account.AccountInfo; import com.google.gerrit.client.account.AccountInfo.AvatarInfo; import com.google.gerrit.client.changes.Util; import com.google.gerrit.client.rpc.RestApi; import com.google.gwt.event.dom.client.LoadEvent; import com.google.gwt.event.dom.client.LoadHandler; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.dom.client.MouseOverEvent; import com.google.gwt.event.dom.client.MouseOverHandler; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.UIObject; public class AvatarImage extends Image implements LoadHandler { public AvatarImage() { setVisible(false); addLoadHandler(this); } /** A default sized avatar image. */ public AvatarImage(AccountInfo account) { this(account, AccountInfo.AvatarInfo.DEFAULT_SIZE, true); } /** * An avatar image for the given account using the requested size. * * @param account The account in which we are interested * @param size A requested size. Note that the size can be ignored depending * on the avatar provider. A size <= 0 indicates to let the provider * decide a default size. */ public AvatarImage(AccountInfo account, int size) { this(account, size, true); } /** * An avatar image for the given account using the requested size. * * @param account The account in which we are interested * @param size A requested size. Note that the size can be ignored depending * on the avatar provider. A size <= 0 indicates to let the provider * decide a default size. * @param addPopup show avatar popup with user info on hovering over the * avatar image */ public AvatarImage(AccountInfo account, int size, boolean addPopup) { addLoadHandler(this); setAccount(account, size, addPopup); } public void setAccount(AccountInfo account, int size, boolean addPopup) { if (account == null) { setVisible(false); } else if (isGerritServer(account)) { setVisible(true); setResource(Gerrit.RESOURCES.gerritAvatar26()); } else if (account.has_avatar_info()) { setVisible(false); AvatarInfo info = account.avatar(size); if (info != null) { setWidth(info.width() > 0 ? info.width() + "px" : ""); setHeight(info.height() > 0 ? info.height() + "px" : ""); setUrl(info.url()); popup(account, addPopup); } else if (account.email() != null) { loadAvatar(account, size, addPopup); } } else if (account.email() != null) { loadAvatar(account, size, addPopup); } else { setVisible(false); } } private void loadAvatar(AccountInfo account, int size, boolean addPopup) { // TODO Kill /accounts/*/avatar URL. String u = account.email(); if (Gerrit.isSignedIn() && u.equals(Gerrit.getUserAccount().getPreferredEmail())) { u = "self"; } RestApi api = new RestApi("/accounts/").id(u).view("avatar"); if (size > 0) { api.addParameter("s", size); setSize("", size + "px"); } setVisible(false); setUrl(api.url()); popup(account, addPopup); } private void popup(AccountInfo account, boolean addPopup) { if (addPopup) { PopupHandler popupHandler = new PopupHandler(account, this); addMouseOverHandler(popupHandler); addMouseOutHandler(popupHandler); } } @Override public void onLoad(LoadEvent event) { setVisible(true); } private static boolean isGerritServer(AccountInfo account) { return account._account_id() == 0 && Util.C.messageNoAuthor().equals(account.name()); } private static class PopupHandler implements MouseOverHandler, MouseOutHandler { private final AccountInfo account; private final UIObject target; private UserPopupPanel popup; private Timer showTimer; private Timer hideTimer; public PopupHandler(AccountInfo account, UIObject target) { this.account = account; this.target = target; } private UserPopupPanel createPopupPanel(AccountInfo account) { UserPopupPanel popup = new UserPopupPanel(account, false, false); popup.addDomHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent event) { scheduleShow(); } }, MouseOverEvent.getType()); popup.addDomHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent event) { scheduleHide(); } }, MouseOutEvent.getType()); return popup; } @Override public void onMouseOver(MouseOverEvent event) { scheduleShow(); } @Override public void onMouseOut(MouseOutEvent event) { scheduleHide(); } private void scheduleShow() { if (hideTimer != null) { hideTimer.cancel(); hideTimer = null; } if ((popup != null && popup.isShowing() && popup.isVisible()) || showTimer != null) { return; } showTimer = new Timer() { @Override public void run() { if (popup == null) { popup = createPopupPanel(account); } if (!popup.isShowing() || !popup.isVisible()) { popup.showRelativeTo(target); } } }; showTimer.schedule(600); } private void scheduleHide() { if (showTimer != null) { showTimer.cancel(); showTimer = null; } if (popup == null || !popup.isShowing() || !popup.isVisible() || hideTimer != null) { return; } hideTimer = new Timer() { @Override public void run() { popup.hide(); } }; hideTimer.schedule(50); } } }