package org.gcube.portlets.user.newsfeed.client.panels; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import org.gcube.common.portal.GCubePortalConstants; import org.gcube.portal.databook.client.GCubeSocialNetworking; import org.gcube.portal.databook.client.util.Encoder; import org.gcube.portal.databook.shared.Attachment; import org.gcube.portal.databook.shared.ClientFeed; import org.gcube.portal.databook.shared.Comment; import org.gcube.portal.databook.shared.EnhancedFeed; import org.gcube.portal.databook.shared.Feed; import org.gcube.portal.databook.shared.FeedType; import org.gcube.portal.databook.shared.Like; import org.gcube.portal.databook.shared.PrivacyLevel; import org.gcube.portal.databook.shared.ShowUserStatisticAction; import org.gcube.portal.databook.shared.UserInfo; import org.gcube.portlets.user.gcubewidgets.client.ClientScopeHelper; import org.gcube.portlets.user.newsfeed.client.FilterType; import org.gcube.portlets.user.newsfeed.client.NewsFeed; import org.gcube.portlets.user.newsfeed.client.NewsService; import org.gcube.portlets.user.newsfeed.client.NewsServiceAsync; import org.gcube.portlets.user.newsfeed.client.event.AddCommentEvent; import org.gcube.portlets.user.newsfeed.client.event.AddCommentEventHandler; import org.gcube.portlets.user.newsfeed.client.event.AddLikeEvent; import org.gcube.portlets.user.newsfeed.client.event.AddLikeEventHandler; import org.gcube.portlets.user.newsfeed.client.event.DeleteCommentEvent; import org.gcube.portlets.user.newsfeed.client.event.DeleteCommentEventHandler; import org.gcube.portlets.user.newsfeed.client.event.DeleteFeedEvent; import org.gcube.portlets.user.newsfeed.client.event.DeleteFeedEventHandler; import org.gcube.portlets.user.newsfeed.client.event.EditCommentEvent; import org.gcube.portlets.user.newsfeed.client.event.EditCommentEventHandler; import org.gcube.portlets.user.newsfeed.client.event.OpenFeedEvent; import org.gcube.portlets.user.newsfeed.client.event.OpenFeedEventHandler; import org.gcube.portlets.user.newsfeed.client.event.PageBusEvents; import org.gcube.portlets.user.newsfeed.client.event.SeeCommentsEvent; import org.gcube.portlets.user.newsfeed.client.event.SeeCommentsEventHandler; import org.gcube.portlets.user.newsfeed.client.event.SeeLikesEvent; import org.gcube.portlets.user.newsfeed.client.event.SeeLikesEventHandler; import org.gcube.portlets.user.newsfeed.client.event.ShowMoreUpdatesEvent; import org.gcube.portlets.user.newsfeed.client.event.ShowMoreUpdatesEventHandler; import org.gcube.portlets.user.newsfeed.client.event.ShowNewUpdatesEvent; import org.gcube.portlets.user.newsfeed.client.event.ShowNewUpdatesEventHandler; import org.gcube.portlets.user.newsfeed.client.event.UnLikeEvent; import org.gcube.portlets.user.newsfeed.client.event.UnLikeEventHandler; import org.gcube.portlets.user.newsfeed.client.ui.FilterPanel; import org.gcube.portlets.user.newsfeed.client.ui.LoadingText; import org.gcube.portlets.user.newsfeed.client.ui.NewFeedsAvailable; import org.gcube.portlets.user.newsfeed.client.ui.ResultsFor; import org.gcube.portlets.user.newsfeed.client.ui.ShowMoreFeeds; import org.gcube.portlets.user.newsfeed.client.ui.SingleComment; import org.gcube.portlets.user.newsfeed.client.ui.TweetTemplate; import org.gcube.portlets.user.newsfeed.shared.MoreFeedsBean; import org.gcube.portlets.user.newsfeed.shared.NewsConstants; import org.gcube.portlets.user.newsfeed.shared.OperationResult; import org.gcube.portlets.user.newsfeed.shared.UserSettings; import org.gcube.portlets.widgets.userselection.client.UserSelectionDialog; import org.gcube.portlets.widgets.userselection.client.events.SelectedUserEvent; import org.gcube.portlets.widgets.userselection.client.events.SelectedUserEventHandler; import org.gcube.portlets.widgets.userselection.client.events.UsersFetchedEvent; import org.gcube.portlets.widgets.userselection.shared.ItemSelectableBean; import org.jsonmaker.gwt.client.base.Defaults; import com.github.gwtbootstrap.client.ui.Row; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.Location; import com.google.gwt.user.client.Window.ScrollEvent; import com.google.gwt.user.client.Window.ScrollHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.HasAlignment; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import net.eliasbalasis.tibcopagebus4gwt.client.PageBusAdapterException; /** * * @author Massimiliano Assante, ISTI-CNR * */ public class NewsFeedPanel extends Composite { /** * the current scope on the client can be static */ private static String currentScope; /** * Create a remote service proxy to talk to the server-side News service. */ private final NewsServiceAsync newsService = GWT.create(NewsService.class); private final HandlerManager eventBus = new HandlerManager(null); private VerticalPanel mainPanel = new VerticalPanel(); private HorizontalPanel filterPanelWrapper = new HorizontalPanel(); private FilterPanel filterPanel; private SimplePanel newUpdatesPanel = new SimplePanel(); private Row showMoreUpdatesPanel = new Row(); private VerticalPanel newsPanel = new VerticalPanel(); private NewFeedsAvailable newsFeedAlert; private static final String warning = GWT.getModuleBaseURL() + "../images/warning_blue.png"; private static final String spacer = GWT.getModuleBaseURL() + "../images/feeds-spacer.gif"; public static final String loading = GWT.getModuleBaseURL() + "../images/feeds-loader.gif"; public static final String GET_OID_PARAMETER = "oid"; public static final String LIKE_LABEL = "Like"; public static final String LIKED_LABEL = "Liked"; public static final String COMMENT_LABEL = "Reply"; public static final String SHARE_FWD_LABEL = "Share"; private static final int SEARCHED_FEEDS_TO_SHOW = 10; private static final int FEEDS_RELATED_TO_USER_STATISTICS_TO_SHOW = 10; private String vreLabel; private boolean showFeedTimelineSource = false; private boolean isInfrastructure = false; private int delayMillis = 300000; //5 minutes by default (is read from a configuration file in the first async callback) private int currNewUpdatesNo = 0; private boolean isFirstTweet = false; // is user searching for something? private boolean isSearch = false; // the current query (if isSearch is true) protected String currentQuery; // is the user seeing her statistics? private boolean isFeedsRelatedToStatistics = false; // the feeds related to user statistics to show protected ShowUserStatisticAction relatedFeedsToUserStatisticsToShow; private LoadingText loadingIcon = new LoadingText(); private Image loadingImage; private UserInfo myUserInfo; private FilterType currentFilter; private Timer feedsTimer; private ShowMoreFeeds showMoreWidget; //needed to know the next range start private Integer fromStartingPoint; private ArrayList allUpdates = new ArrayList(); private ArrayList tempCacheNewUpdates = new ArrayList(); /** * events binder */ private void bind() { eventBus.addHandler(ShowMoreUpdatesEvent.TYPE, new ShowMoreUpdatesEventHandler() { @Override public void onShowMoreUpdatesClick(ShowMoreUpdatesEvent event) { doShowMoreUpdates(); } }); eventBus.addHandler(ShowNewUpdatesEvent.TYPE, new ShowNewUpdatesEventHandler() { @Override public void onShowNewUpdatesClick(ShowNewUpdatesEvent event) { doShowCachedNewUpdates(); } }); eventBus.addHandler(AddLikeEvent.TYPE, new AddLikeEventHandler() { @Override public void onAddLike(AddLikeEvent event) { doAddLike( event.getOwner(), event.getFeedId()); } }); eventBus.addHandler(UnLikeEvent.TYPE, new UnLikeEventHandler() { @Override public void onUnLike(UnLikeEvent event) { doUnLike(event.getOwner(), event.getFeedId()); } }); eventBus.addHandler(AddCommentEvent.TYPE, new AddCommentEventHandler() { @Override public void onAddComment(AddCommentEvent event) { doAddComment(event.getOwner(), event.getText(), event.getMentionedUsers()); } }); eventBus.addHandler(EditCommentEvent.TYPE, new EditCommentEventHandler() { @Override public void onEditComment(EditCommentEvent event) { doEditComment(event.getOwner(), event.getCommentInstance(), event.getCommentPanel()); } }); eventBus.addHandler(SelectedUserEvent.TYPE, new SelectedUserEventHandler() { @Override public void onSelectedUser(SelectedUserEvent event) { final String profilePageURL = GCubePortalConstants.PREFIX_GROUP_URL + ClientScopeHelper.extractOrgFriendlyURL(Location.getHref()) +GCubePortalConstants.USER_PROFILE_FRIENDLY_URL; Location.assign(profilePageURL+"?"+ Encoder.encode(GCubeSocialNetworking.USER_PROFILE_OID)+"="+ Encoder.encode(event.getSelectedUser().getId())); } }); eventBus.addHandler(SeeLikesEvent.TYPE, new SeeLikesEventHandler() { @Override public void onSeeLikes(SeeLikesEvent event) { doShowLikes(event.getFeedId()); } }); eventBus.addHandler(SeeCommentsEvent.TYPE, new SeeCommentsEventHandler() { @Override public void onSeeComments(SeeCommentsEvent event) { doShowComments(event.getOwner(), event.isCommentForm2Add()); } }); eventBus.addHandler(DeleteCommentEvent.TYPE, new DeleteCommentEventHandler() { @Override public void onDeleteComment(DeleteCommentEvent event) { doDeleteComment(event.getOwner(), event.getCommentId()); } }); eventBus.addHandler(DeleteFeedEvent.TYPE, new DeleteFeedEventHandler() { @Override public void onDeleteFeed(DeleteFeedEvent event) { doDeleteFeed(event.getToDelete()); } }); eventBus.addHandler(OpenFeedEvent.TYPE, new OpenFeedEventHandler() { @Override public void onOpenFeed(OpenFeedEvent event) { doShowFeed(event.getToShow()); } }); } /** * */ public NewsFeedPanel() { bind(); mainPanel.setWidth("100%"); mainPanel.add(filterPanelWrapper); filterPanelWrapper.setVisible(false); mainPanel.add(newUpdatesPanel); mainPanel.add(newsPanel); filterPanel = new FilterPanel(this, newsService); filterPanelWrapper.add(filterPanel); initWidget(mainPanel); newsPanel.clear(); newsPanel.setWidth("100%"); showMoreUpdatesPanel.setWidth("60%"); newsPanel.setHeight("300px"); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_CENTER); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); loadingImage = new Image(loading); newsPanel.add(loadingIcon); //CheckSession.getInstance().startPolling(); isSearch = false; isFeedsRelatedToStatistics = false; newsService.getUserSettings(new AsyncCallback() { @Override public void onFailure(Throwable caught) { } @Override public void onSuccess(UserSettings result) { myUserInfo = result.getUserInfo(); delayMillis = result.getRefreshingTimeInMillis(); vreLabel = result.getVreLabel(); currentScope = result.getCurrentScope(); if (result.getUserInfo().getUsername().equals(NewsConstants.TEST_USER)) { doStopFeedsTimer(); doShowSessionExpired(); } else { GWT.log("checking params "); if (getFeedToShowId() != null) { String feedKey = getFeedToShowId(); showSingleFeed(feedKey); filterPanel.removeFilterSelected(); } else if (getHashtagParam() != null) { String hashtag = ""; try { hashtag = Encoder.decode(getHashtagParam()); } catch (Exception e) { newsPanel.clear(); newsPanel.add(new HTML("
" + "We're sorry, it seems you used an invalid character, please check the hashtag
")); return; } showFeedsByHashtag(hashtag); filterPanel.removeFilterSelected(); } else if (getSearchParam() != null) { String query = ""; try { query = Encoder.decode(getSearchParam()); currentQuery = query; } catch (Exception e) { newsPanel.clear(); newsPanel.add(new HTML("
" + "We're sorry, it seems you used an invalid character, please check the query
")); return; } // show isSearch = true; showFeedsSearch(query, 0, SEARCHED_FEEDS_TO_SHOW); filterPanel.removeFilterSelected(); }else if(getShowUserStatisticParam() != null){ String action = ""; try { action = Encoder.decode(getShowUserStatisticParam()); relatedFeedsToUserStatisticsToShow = ShowUserStatisticAction.valueOf(action); } catch (Exception e) { newsPanel.clear(); newsPanel.add(new HTML("
" + "We're sorry, it seems you used an invalid character
")); return; } isFeedsRelatedToStatistics = true; showUserStatisticsRelatedFeeds(relatedFeedsToUserStatisticsToShow, 0, FEEDS_RELATED_TO_USER_STATISTICS_TO_SHOW); filterPanel.removeFilterSelected(); } else { showAllUpdatesFeeds(); } currentFilter = FilterType.ALL_UPDATES; } //adjustments in the UI Depending on the scope if (result.isInfrastructure()) { //filterPanelWrapper.setVisible(getFeedToShowId() == null); showFeedTimelineSource = result.isShowTimelineSourceLabel(); isInfrastructure = true; } } }); feedsTimer = new Timer() { @Override public void run() { checkForNewUpdates(); } }; feedsTimer.scheduleRepeating(delayMillis); //this is for the automatic scroll of feeds Window.addWindowScrollHandler(new ScrollHandler() { @Override public void onWindowScroll(ScrollEvent event) { boolean isInView = isScrolledIntoView(showMoreWidget); if (isInView) { eventBus.fireEvent(new ShowMoreUpdatesEvent()); } } }); } /** * stop the feeds timer (when session expires) */ private void doStopFeedsTimer() { feedsTimer.cancel(); } /** * */ private void checkForNewUpdates() { switch (currentFilter) { case ALL_UPDATES: checkAllUpdatesFeeds(); break; case CONNECTIONS: showOnlyConnectionsFeeds(); break; case MINE: showOnlyMyFeeds(); break; default: break; } } /** * check if it has to show just one feed * @return */ private String getFeedToShowId() { return Window.Location.getParameter(GET_OID_PARAMETER); } /** * check if it has to show the feeds given an hashtag * @return */ private String getHashtagParam() { return Window.Location.getParameter(Encoder.encode(GCubeSocialNetworking.HASHTAG_OID)); } /** * Check if some user statistic related feeds must be shown * @return */ private String getShowUserStatisticParam(){ return Window.Location.getParameter(Encoder.encode(GCubeSocialNetworking.SHOW_STATISTICS_ACTION_OID)); } /** * check if it has to show the feeds given a query * @return */ private String getSearchParam() { return Window.Location.getParameter(Encoder.encode(GCubeSocialNetworking.SEARCH_OID)); } /** * used from notification referrals (see this Post) * @param feedKey */ private void showSingleFeed(String feedKey) { newsPanel.clear(); newsService.getSingleFeed(feedKey, new AsyncCallback() { @Override public void onSuccess(EnhancedFeed result) { if (result.getFeed().getType() == FeedType.DISABLED) { final String profilePageURL = GCubePortalConstants.PREFIX_GROUP_URL + ClientScopeHelper.extractOrgFriendlyURL(Location.getHref()) +GCubePortalConstants.USER_PROFILE_FRIENDLY_URL; String usrLink = ""+result.getFeed().getFullName()+ " "; newsPanel.add(new HTML("
" + "We're sorry, "+ usrLink +" removed the post in the meantime!
")); } else { mainPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); newsPanel.add(new ResultsFor("selected post", "")); newsPanel.setHeight(""); newsPanel.add(new TweetTemplate(true, true, myUserInfo, result, eventBus)); } newsPanel.add(new Image(spacer)); } @Override public void onFailure(Throwable caught) { showProblems(); } }); } /** * check for updates */ private void checkAllUpdatesFeeds() { newsService.getUserSettings(new AsyncCallback() { @Override public void onFailure(Throwable caught) { doStopFeedsTimer(); } @Override public void onSuccess(UserSettings result) { if (result.getUserInfo().getUsername().equals(NewsConstants.TEST_USER)) { doStopFeedsTimer(); doShowSessionExpired(); } /** * this check avoids the 2 tabs open in 2 different scope, if the previous tab was open at VRE Level and then antoher * is open at infra level the first tab stops checking for updates */ if (result.getCurrentScope().compareTo(currentScope) == 0) { newsService.getAllUpdateUserFeeds(NewsConstants.FEEDS_NO_PER_CATEGORY, new AsyncCallback>() { @Override public void onSuccess(ArrayList feeds) { if (feeds != null && allUpdates.size() > 0) { Date myLastUpdateTime = allUpdates.get(0).getFeed().getTime(); //this is the last update in the View GWT.log("Last Mine: "+allUpdates.get(0).getFeed().getDescription()); GWT.log("Last Retr.: "+feeds.get(0).getFeed().getDescription()); tempCacheNewUpdates = new ArrayList(); //need to clear it everytime i check (in case someone deleted the updated in the meanwhile) //check if there are new updates (enter the while) and put them in a temporary cache for displaying on user click int i = 0; while (i < feeds.size() && feeds.get(i).getFeed().getTime().after(myLastUpdateTime)) { tempCacheNewUpdates.add(feeds.get(i)); i++; } /* currNewUpdatesNo keeps the number of updates to be added on user clicks, * i keeps the total number as it arrives, * if they differ you got to refresh the updates to show the new number */ if (currNewUpdatesNo < i) { //add the current "show new updates" alert panel if not present if (newsFeedAlert == null) { newsFeedAlert = new NewFeedsAvailable(i, eventBus); newUpdatesPanel.add(newsFeedAlert); } else //update it otherwise newsFeedAlert.updateNewUpdatesNo(i); currNewUpdatesNo = i; } } } @Override public void onFailure(Throwable caught) {} }); } } }); } /** * get the hashtagged feeds * @param hashtag to look for */ private void showFeedsByHashtag(final String hashtag) { showLoader(); newsService.getUserSettings(new AsyncCallback() { @Override public void onFailure(Throwable caught) { doStopFeedsTimer(); } @Override public void onSuccess(UserSettings result) { if (result.getUserInfo().getUsername().equals(NewsConstants.TEST_USER)) { doStopFeedsTimer(); doShowSessionExpired(); } else { /** * this check avoids the 2 tabs open in 2 different scope, if the previous tab was open at VRE Level and then antoher * is open at infra level the first tab stops checking for updates */ if (result.getCurrentScope().compareTo(currentScope) == 0) { newsService.getFeedsByHashtag(hashtag, new AsyncCallback>() { @Override public void onSuccess(ArrayList feeds) { filterPanelWrapper.setVisible(false); newsPanel.clear(); if (feeds != null) { if (feeds.size() == 0) { newsPanel.add(new ResultsFor("results for", hashtag)); newsPanel.add(new HTML("
" + "Sorry, looks like we found no updates with topic: " + hashtag +"
")); isFirstTweet = true; } else { newsPanel.setHeight(""); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); newsPanel.add(new ResultsFor("results for", hashtag)); for (EnhancedFeed feed : feeds) { newsPanel.add(new TweetTemplate(false, showFeedTimelineSource, myUserInfo, feed, eventBus)); //in the view } if (feeds.size() < 5) { newsPanel.add(new Image(spacer)); } isFirstTweet = false; } } else { showProblems(); } } @Override public void onFailure(Throwable caught) { showProblems(); } }); } } } }); } /** * Called when a user wants to show some feeds related to her statistics */ private void showUserStatisticsRelatedFeeds(final ShowUserStatisticAction relatedFeedsToUserStatisticsToShow, final int from, final int to) { // show loader while waiting showLoader(); // stop asking for feeds doStopFeedsTimer(); final String actionToPrint = relatedFeedsToUserStatisticsToShow.getHumanFriendlyAction(); newsService.getUserSettings(new AsyncCallback() { @Override public void onFailure(Throwable caught) { } @Override public void onSuccess(UserSettings result) { if (result.getUserInfo().getUsername().equals(NewsConstants.TEST_USER)) { doShowSessionExpired(); } else { /** * this check avoids the 2 tabs open in 2 different scope, if the previous tab was open at VRE Level and then antoher * is open at infra level the first tab stops checking for updates */ if (result.getCurrentScope().compareTo(currentScope) == 0) { newsService.getFeedsRelatedToUserStatistics(relatedFeedsToUserStatisticsToShow, from, to, new AsyncCallback>() { @Override public void onSuccess(ArrayList feeds) { filterPanelWrapper.setVisible(false); newsPanel.clear(); if (feeds != null) { GWT.log("Retrieved " + feeds.size() + " hits for search."); if (feeds.size() == 0) { newsPanel.add(new ResultsFor("", actionToPrint)); newsPanel.add(new HTML("
" + "Sorry, looks like we found no match for action : " + actionToPrint +"
")); } else { newsPanel.setHeight(""); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); newsPanel.add(new ResultsFor("", actionToPrint)); for (EnhancedFeed feed : feeds) { newsPanel.add(new TweetTemplate(false, showFeedTimelineSource, myUserInfo, feed, eventBus)); //in the view // save them (they will be used when asking more feeds) allUpdates.add(feed); } if (feeds.size() < 5) { newsPanel.add(new Image(spacer)); } // add widget to lookup more feeds: if the size of the returned data is less // than the required disable this feature. if(feeds.size() == FEEDS_RELATED_TO_USER_STATISTICS_TO_SHOW){ showMoreWidget = new ShowMoreFeeds(eventBus); showMoreUpdatesPanel.add(showMoreWidget); newsPanel.add(showMoreUpdatesPanel); } } } else { showProblems(); } } @Override public void onFailure(Throwable caught) { showProblems(); } }); } } } }); } /** * Called when a user search something */ private void showFeedsSearch(final String query, final int from, final int to) { // show loader while waiting showLoader(); // stop asking for feeds doStopFeedsTimer(); newsService.getUserSettings(new AsyncCallback() { @Override public void onFailure(Throwable caught) { } @Override public void onSuccess(UserSettings result) { if (result.getUserInfo().getUsername().equals(NewsConstants.TEST_USER)) { doShowSessionExpired(); } else { /** * this check avoids the 2 tabs open in 2 different scope, if the previous tab was open at VRE Level and then antoher * is open at infra level the first tab stops checking for updates */ if (result.getCurrentScope().compareTo(currentScope) == 0) { newsService.getFeedsByQuery(query, from, to, new AsyncCallback>() { @Override public void onSuccess(ArrayList feeds) { filterPanelWrapper.setVisible(false); newsPanel.clear(); if (feeds != null) { GWT.log("Retrieved " + feeds.size() + " hits for search."); if (feeds.size() == 0) { newsPanel.add(new ResultsFor("Results for query ", query)); newsPanel.add(new HTML("
" + "Sorry, looks like we found no match for: " + query +"
")); } else { newsPanel.setHeight(""); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); newsPanel.add(new ResultsFor("Results for query ", query)); for (EnhancedFeed feed : feeds) { newsPanel.add(new TweetTemplate(false, showFeedTimelineSource, myUserInfo, feed, eventBus)); //in the view // save them (they will be used when asking more feeds) allUpdates.add(feed); } if (feeds.size() < 5) { newsPanel.add(new Image(spacer)); } // add widget to lookup more feeds: if the size of the returned data is less // than the required disable this feature. if(feeds.size() == SEARCHED_FEEDS_TO_SHOW){ showMoreWidget = new ShowMoreFeeds(eventBus); showMoreUpdatesPanel.add(showMoreWidget); newsPanel.add(showMoreUpdatesPanel); } } } else { showProblems(); } } @Override public void onFailure(Throwable caught) { showProblems(); } }); } } } }); } /** * called when a user click on the are new updates */ protected void doShowCachedNewUpdates() { newUpdatesPanel.clear(); //remove the alert panel newsFeedAlert = null; //reset the alert panel and other needed vars currNewUpdatesNo = 0; //need to put them in reverse order; for (int i = tempCacheNewUpdates.size(); i > 0; i--) { EnhancedFeed feed = tempCacheNewUpdates.get(i-1); final TweetTemplate tt = new TweetTemplate(myUserInfo, feed, eventBus, true); newsPanel.insert(tt, 0); //insert in the view allUpdates.add(0, feed); //insert in the model //timer for the transition Timer t = new Timer() { @Override public void run() { tt.setcontentAreaStyle("visible"); // alert the user-statistics portlet to update statistics in case // one or more feed belongs to user himself if(tt.isUser()){ try{ NewsFeed.pageBusAdapter.PageBusPublish(PageBusEvents.postIncrement, "", Defaults.STRING_JSONIZER); int numComments = tt.numberOfComments(); int numLikes = tt.numberOfLikes(); for(int i = 0; i < numComments; i++) NewsFeed.pageBusAdapter.PageBusPublish(PageBusEvents.commentsIncrement, "", Defaults.STRING_JSONIZER); for(int i = 0; i < numLikes; i++) NewsFeed.pageBusAdapter.PageBusPublish(PageBusEvents.likesIncrement, "", Defaults.STRING_JSONIZER); }catch (PageBusAdapterException ex) { GWT.log(ex.toString()); } } } }; t.schedule(100); } //after that I remove the ($updatesNo) from Window Title String currTitle = Document.get().getTitle(); Document.get().setTitle(currTitle.startsWith("(") ? currTitle.substring(4) : currTitle); } /** * used when adding directly a feed from the UI (IPC) * @param userid * @param fullName * @param thumbURL * @param description */ public void addJustAddedFeed(ClientFeed cFeed) { // build up the feed Feed feed = new Feed( cFeed.getKey(), FeedType.SHARE, cFeed.getUserid(), cFeed.getTime(), "", cFeed.getUri(), cFeed.getLinkUrlThumbnail(), cFeed.getDescription(), PrivacyLevel.CONNECTION, cFeed.getFullName(), cFeed.getEmail(), cFeed.getThumbnailURL(), cFeed.getLinkTitle(), cFeed.getLinkDescription(), cFeed.getLinkHost()); // set multi-attachments property boolean multiAttachments = cFeed.getAttachments() != null; feed.setMultiFileUpload(multiAttachments); //false because he could not have liked this yet and true because is the current user's EnhancedFeed toAdd = new EnhancedFeed(feed, false, true); // be careful when converting from List<> to ArrayList<> ... ArrayList attachments = multiAttachments ? new ArrayList(cFeed.getAttachments()) : null; toAdd.setAttachments(attachments); // build up the post template final TweetTemplate tt = new TweetTemplate(myUserInfo, toAdd, eventBus, true); if (isFirstTweet) { newsPanel.clear(); newsPanel.add(new Image(spacer)); isFirstTweet = false; } newsPanel.insert(tt, 0); Timer t = new Timer() { @Override public void run() { tt.setcontentAreaStyle("visible"); } }; // show after half a second t.schedule(500); //insert it also in the model so that the user who created it do not get notified about this new update allUpdates.add(0, toAdd); } /** * All Updates */ public void showAllUpdatesFeeds() { showLoader(); newsService.getAllUpdateUserFeeds(NewsConstants.FEEDS_NO_PER_CATEGORY, new AsyncCallback>() { @Override public void onSuccess(ArrayList feeds) { newsPanel.clear(); if (feeds != null) { if (feeds.size() == 0) { if (!isInfrastructure) { newsPanel.add(new HTML("
" + "Looks like nobody posted anything yet. Are you willing to be the first?
" + "You may begin by posting a message!
")); } else { newsPanel.add(new HTML("
" + "Looks like we've got nothing for you at the moment.
" + "You may begin by joining some of the available " + "
"+vreLabel+"s.
")); } isFirstTweet = true; } else { newsPanel.setHeight(""); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); for (EnhancedFeed feed : feeds) { newsPanel.add(new TweetTemplate(false, showFeedTimelineSource, myUserInfo, feed, eventBus)); //in the view allUpdates.add(feed); //in the model } if (feeds.size() < 5) { newsPanel.add(new Image(spacer)); } //if you are showing more than feedsMaxPerCategory-1 feeds there is probably more if (feeds.size() >= NewsConstants.FEEDS_MAX_PER_CATEGORY-1 && (!isInfrastructure)) { GWT.log("Show MORE " + NewsConstants.FEEDS_NO_PER_CATEGORY); showMoreWidget = new ShowMoreFeeds(eventBus); showMoreUpdatesPanel.add(showMoreWidget); newsPanel.add(showMoreUpdatesPanel); } isFirstTweet = false; } } else { showProblems(); } } @Override public void onFailure(Throwable caught) { newsPanel.clear(); newsPanel.add(new HTML("
" + "Ops! There were problems while retrieving your feeds!.
" + "Please try again in a short while.
")); } }); } /** * called when a user scroll down the page to the bottom */ protected void doShowMoreUpdates() { showMoreUpdatesPanel.remove(0); loadingImage.getElement().getStyle().setMargin(10, Unit.PX); showMoreUpdatesPanel.add(loadingIcon); if(isSearch){ GWT.log("Going to request more feeds for this search"); // start position int start = allUpdates.size(); GWT.log("StartingPoint = " + start); newsService.getFeedsByQuery(currentQuery, start, SEARCHED_FEEDS_TO_SHOW , new AsyncCallback>() { @Override public void onSuccess(ArrayList feeds){ newsPanel.remove(showMoreUpdatesPanel); if (feeds != null) { GWT.log("There are " + feeds.size() + " more feeds"); for (EnhancedFeed feed : feeds) { // avoid to insert same data if(!isFeedPresent(feed)){ newsPanel.add(new TweetTemplate(false, showFeedTimelineSource, myUserInfo, feed, eventBus)); //in the view allUpdates.add(feed); } } // clear panel showMoreUpdatesPanel.clear(); // check if we can ask for other data if(feeds.size() == SEARCHED_FEEDS_TO_SHOW){ GWT.log("It seems there are no more feeds for this query. Stop asking further"); showMoreWidget = new ShowMoreFeeds(eventBus); showMoreUpdatesPanel.add(showMoreWidget); newsPanel.add(showMoreUpdatesPanel); }else{ showMoreWidget = null; } } } @Override public void onFailure(Throwable caught) { showMoreUpdatesPanel.clear(); newsPanel.add(new HTML("
" + "Ops! There were problems while retrieving your feeds!.
" + "Please try again in a short while.
")); } }); }else if(isFeedsRelatedToStatistics){ GWT.log("Going to request more feeds for this user's statisics"); // start position int start = allUpdates.size(); GWT.log("StartingPoint = " + start); newsService.getFeedsRelatedToUserStatistics(relatedFeedsToUserStatisticsToShow, start, FEEDS_RELATED_TO_USER_STATISTICS_TO_SHOW , new AsyncCallback>() { @Override public void onSuccess(ArrayList feeds){ newsPanel.remove(showMoreUpdatesPanel); if (feeds != null) { GWT.log("There are " + feeds.size() + " more feeds"); for (EnhancedFeed feed : feeds) { // avoid to insert same data if(!isFeedPresent(feed)){ newsPanel.add(new TweetTemplate(false, showFeedTimelineSource, myUserInfo, feed, eventBus)); //in the view allUpdates.add(feed); } } // clear panel showMoreUpdatesPanel.clear(); // check if we can ask for other data if(feeds.size() == FEEDS_RELATED_TO_USER_STATISTICS_TO_SHOW){ GWT.log("It seems there are no more feeds for this query. Stop asking further"); showMoreWidget = new ShowMoreFeeds(eventBus); showMoreUpdatesPanel.add(showMoreWidget); newsPanel.add(showMoreUpdatesPanel); }else{ showMoreWidget = null; } } } @Override public void onFailure(Throwable caught) { showMoreUpdatesPanel.clear(); newsPanel.add(new HTML("
" + "Ops! There were problems while retrieving your feeds!.
" + "Please try again in a short while.
")); } }); } else{ int from = (fromStartingPoint == null) ? allUpdates.size()+1 : fromStartingPoint; final int quantity = 10; GWT.log("StartingPoint = " + from); newsService.getMoreFeeds(from, quantity, new AsyncCallback() { @Override public void onSuccess(MoreFeedsBean rangeFeeds) { newsPanel.remove(showMoreUpdatesPanel); if (rangeFeeds.getFeeds() != null) { fromStartingPoint = rangeFeeds.getLastReturnedFeedTimelineIndex(); int c = 1; for (EnhancedFeed feed : rangeFeeds.getFeeds()) { if (!isFeedPresent(feed)) { //avoid possible duplicates newsPanel.add(new TweetTemplate(false, showFeedTimelineSource, myUserInfo, feed, eventBus)); //in the view allUpdates.add(feed); //in the model } c++; } if (c >= quantity) { //there could be more feeds GWT.log("there could be more feeds"); showMoreUpdatesPanel.clear(); showMoreWidget = new ShowMoreFeeds(eventBus); showMoreUpdatesPanel.add(showMoreWidget); newsPanel.add(showMoreUpdatesPanel); } } } @Override public void onFailure(Throwable caught) { showMoreUpdatesPanel.clear(); newsPanel.add(new HTML("
" + "Ops! There were problems while retrieving your feeds!.
" + "Please try again in a short while.
")); } }); } } /** * @param widget the widget to check * @returnn true if the widget is in the visible part of the page */ private boolean isScrolledIntoView(Widget widget) { if (widget != null) { int docViewTop = Window.getScrollTop(); int docViewBottom = docViewTop + Window.getClientHeight(); int elemTop = widget.getAbsoluteTop(); int elemBottom = elemTop + widget.getOffsetHeight(); return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)); } return false; } private boolean isFeedPresent(EnhancedFeed toCheck) { for (EnhancedFeed feed : allUpdates) { if (feed.getFeed().getKey().compareTo(toCheck.getFeed().getKey()) == 0) return true; } return false; } /** * Only User Connections */ public void showOnlyConnectionsFeeds() { showLoader(); newsService.getOnlyConnectionsUserFeeds(new AsyncCallback>() { @Override public void onSuccess(ArrayList feeds) { if (feeds != null) { newsPanel.clear(); if (feeds.size() == 0) { //TODO: provide actual link for Making some friends newsPanel.add(new HTML("
" + "Looks like we've got nothing for you at the moment.
" + "You may begin by adding some friend!
")); isFirstTweet = true; } else { newsPanel.setHeight(""); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); for (EnhancedFeed feed : feeds) newsPanel.add(new TweetTemplate(false, false, myUserInfo, feed, eventBus)); if (feeds.size() < 5) { newsPanel.add(new Image(spacer)); } isFirstTweet = false; } } else showProblems(); } @Override public void onFailure(Throwable caught) { loadingImage.setUrl(warning); newsPanel.add(new HTML("Ops! There were problems while retrieving your feeds! Please try again in a short while")); } }); } /** * Only User Feeds */ public void showOnlyMyFeeds() { showLoader(); newsService.getOnlyMyUserFeeds(new AsyncCallback>() { @Override public void onSuccess(ArrayList feeds) { if (feeds != null) { newsPanel.clear(); if (feeds.size() == 0) { newsPanel.add(new HTML("
" + "Looks like we've got nothing for you at the moment.
" + "You may begin by sharing an update!
")); isFirstTweet = true; } else { newsPanel.setHeight(""); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); for (EnhancedFeed feed : feeds) newsPanel.add(new TweetTemplate(false, showFeedTimelineSource, myUserInfo, feed, eventBus)); if (feeds.size() < 5) { newsPanel.add(new Image(spacer)); } isFirstTweet = false; } } else showProblems(); } @Override public void onFailure(Throwable caught) { loadingImage.setUrl(warning); newsPanel.add(new HTML("Ops! There were problems while retrieving your feeds! Please try again in a short while")); } }); } /** * Only User Liked Feeds */ public void showOnlyLikedFeeds() { showLoader(); newsService.getOnlyLikedFeeds(new AsyncCallback>() { @Override public void onSuccess(ArrayList feeds) { if (feeds != null) { newsPanel.clear(); if (feeds.size() == 0) { newsPanel.add(new HTML("
" + "Looks like we've got nothing for you at the moment.
" + "Set an update as your favorite to see it here
")); isFirstTweet = true; } else { newsPanel.setHeight(""); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP); for (EnhancedFeed feed : feeds) newsPanel.add(new TweetTemplate(false, showFeedTimelineSource, myUserInfo, feed, eventBus)); if (feeds.size() < 5) { newsPanel.add(new Image(spacer)); } isFirstTweet = false; } } else showProblems(); } @Override public void onFailure(Throwable caught) { loadingImage.setUrl(warning); newsPanel.add(new HTML("Ops! There were problems while retrieving your feeds! Please try again in a short while")); } }); } private void showLoader() { newsPanel.clear(); newsPanel.setWidth("100%"); newsPanel.setHeight("300px"); newsPanel.setHorizontalAlignment(HasAlignment.ALIGN_CENTER); newsPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); newsPanel.add(new Image(loading)); } private void showProblems() { newsPanel.clear(); newsPanel.add(new HTML("
" + "Ops! There were problems while retrieving your feeds!.
" + "Looks like we are not able to communicate with the infrastructure,
(or your session expired)
please try again in a short while or refresh the page.
")); } private void doAddLike(final TweetTemplate owner, final String feedId) { newsService.like(feedId, owner.getMyFeedText(), owner.getMyFeedUserId(), new AsyncCallback() { @Override public void onFailure(Throwable caught) {} @Override public void onSuccess(Boolean result) { if (!result) { doShowSessionExpired(); } else{ // alert the User statistics portlet to increment the number of likes got if(owner.isUser()){ try { NewsFeed.pageBusAdapter.PageBusPublish( PageBusEvents.likesIncrement , "" , Defaults.STRING_JSONIZER); } catch (PageBusAdapterException ex) { GWT.log(ex.toString()); } } } } }); } protected void doUnLike(final TweetTemplate owner, String feedId) { newsService.unlike(feedId, owner.getMyFeedText(), owner.getMyFeedUserId(), new AsyncCallback() { @Override public void onFailure(Throwable caught) {} @Override public void onSuccess(Boolean result) { if (!result) { doShowSessionExpired(); }else{ // alert the User statistics portlet to decrement the number of likes got if(owner.isUser()){ try { NewsFeed.pageBusAdapter.PageBusPublish( PageBusEvents.likesDecrement , "" , Defaults.STRING_JSONIZER); } catch (PageBusAdapterException ex) { GWT.log(ex.toString()); } } } } }); } private void doShowSessionExpired() { } private void doShowLikes(final String feedId) { final UserSelectionDialog dlg = new UserSelectionDialog("People who set this as Favorite", eventBus); dlg.center(); dlg.show(); newsService.getAllLikesByFeed(feedId, new AsyncCallback>() { @Override public void onFailure(Throwable caught) { Window.alert("People who liked this could not be retrieved: " + caught.getMessage()); } @Override public void onSuccess(ArrayList result) { ArrayList toShow = new ArrayList(); for (Like like : result) { toShow.add(new ItemSelectableBean(like.getUserid(), like.getFullName(), like.getThumbnailURL())); } eventBus.fireEvent(new UsersFetchedEvent(toShow)); } }); } private void doAddComment(final TweetTemplate owner, String text, HashSet mentionedUsers) { newsService.comment(owner.getFeedKey(), text, mentionedUsers, owner.getMyFeedUserId(), owner.isAppFeed(), new AsyncCallback() { @Override public void onFailure(Throwable caught) { Window.alert("Could not deliver this comment: " + caught.getMessage()); } @Override public void onSuccess(OperationResult result) { if (result != null) { if (!result.isSuccess()) { //CheckSession.showLogoutDialog(); } else { Comment comment = (Comment) result.getObject(); owner.addComment(new SingleComment(comment, owner, (comment.getUserid().equals(myUserInfo.getUsername())))); owner.setCommentingDisabled(false); owner.updateCommentsNumberCount(); owner.showAddCommentForm(false); if(owner.isUser()){ // alert the User statistics portlet to increment the number of comments got try { NewsFeed.pageBusAdapter.PageBusPublish(PageBusEvents.commentsIncrement, "", Defaults.STRING_JSONIZER); } catch (PageBusAdapterException e) { GWT.log(e.toString()); } } } } else { Window.alert("Could not deliver this comment. Please try again in a short while."); } } }); } private void doEditComment(final TweetTemplate owner, Comment edited, final HTMLPanel commentPanel) { newsService.editComment(edited, new AsyncCallback() { @Override public void onFailure(Throwable caught) { Window.alert("Could not edit this comment: " + caught.getMessage()); } @Override public void onSuccess(OperationResult result) { if (result != null) { if (!result.isSuccess()) { //CheckSession.showLogoutDialog(); } else { Comment comment = (Comment) result.getObject(); owner.updateSingleComment(comment, commentPanel); owner.setCommentingDisabled(false); } } else { Window.alert("Could not deliver this comment. Please try again in a short while."); } } }); } private void doShowComments(final TweetTemplate owner, final boolean commentForm2Add) { owner.showLoadingComments(); newsService.getAllCommentsByFeed(owner.getFeedKey(), new AsyncCallback>() { @Override public void onFailure(Throwable caught) { Window.alert("Comments could not be retrieved: " + caught.getMessage()); } @Override public void onSuccess(ArrayList comments) { owner.clearComments(); for (Comment comment :comments) owner.addComment(new SingleComment(comment, owner,(comment.getUserid().equals(myUserInfo.getUsername())))); owner.setCommentsFetched(true); if (commentForm2Add) owner.showAddCommentForm(false); owner.updateCommentsNumberCount(); owner.showAddCommentForm(false); } }); } protected void doDeleteComment(final TweetTemplate owner, String commentId) { newsService.deleteComment(commentId, owner.getFeedKey(), new AsyncCallback() { @Override public void onFailure(Throwable caught) { Window.alert("Comment could not be deleted: " + caught.getMessage()); } @Override public void onSuccess(Boolean result) { if (result) { doShowComments(owner, false); owner.updateCommentsNumberCount(); if(owner.isUser()){ // alert the User statistics portlet to decrement the number of comments got try { NewsFeed.pageBusAdapter.PageBusPublish(PageBusEvents.commentsDecrement, "", Defaults.STRING_JSONIZER); } catch (PageBusAdapterException ex) { GWT.log(ex.toString()); } } } else Window.alert("Comment could not be deleted, please try again in a short while."); } }); } private void doDeleteFeed(final TweetTemplate toDelete) { if (Window.confirm("Are you sure you want to delete this post?")) { newsService.deleteFeed(toDelete.getFeedKey(), new AsyncCallback() { @Override public void onFailure(Throwable caught) { Window.alert("Feed could not be deleted: " + caught.getMessage()); } @Override public void onSuccess(Boolean result) { if (result) { toDelete.removeFromParent(); if(toDelete.isUser()){ try{ // alert the User statistics portlet to decrement the number of user's posts NewsFeed.pageBusAdapter.PageBusPublish(PageBusEvents.postDecrement, "", Defaults.STRING_JSONIZER); // alert the same portlet to decrement the number of likes/replies, if any int numComments = toDelete.numberOfComments(); int numLikes = toDelete.numberOfLikes(); for(int i = 0; i < numComments; i++) NewsFeed.pageBusAdapter.PageBusPublish(PageBusEvents.commentsDecrement, "", Defaults.STRING_JSONIZER); for(int i = 0; i < numLikes; i++) NewsFeed.pageBusAdapter.PageBusPublish(PageBusEvents.likesDecrement, "", Defaults.STRING_JSONIZER); }catch (PageBusAdapterException ex) { GWT.log(ex.toString()); } } } else Window.alert("Feed could not be deleted, please try again in a short while."); } }); } } private void doShowFeed(final TweetTemplate toShow) { String feedKey = toShow.getFeedKey(); Window.Location.assign(Window.Location.getHref() + ((Window.Location.getHref().contains("?")) ? "&oid="+feedKey : "?oid="+feedKey)); } /** * set the filter type status for automatic reloading of tweets * @param currentFilter */ public void setCurrentFilter(FilterType currentFilter) { this.currentFilter = currentFilter; } /** * * @return the current scope on the client */ public static String getCurrentScope() { return currentScope; } }