/**
* Copyright (c) 2008-2010 The Sakai Foundation
*
* Licensed under the Educational Community 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.osedu.org/licenses/ECL-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 org.sakaiproject.profile2.tool.pages;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.PageableListView;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigator;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.model.StringResourceModel;
import org.sakaiproject.profile2.model.Person;
import org.sakaiproject.profile2.tool.components.IconWithClueTip;
import org.sakaiproject.profile2.tool.components.ProfileImageRenderer;
import org.sakaiproject.profile2.tool.components.ProfileStatusRenderer;
import org.sakaiproject.profile2.tool.models.FriendAction;
import org.sakaiproject.profile2.tool.models.StringModel;
import org.sakaiproject.profile2.tool.pages.windows.AddFriend;
import org.sakaiproject.profile2.util.ProfileConstants;
import org.sakaiproject.profile2.util.ProfileUtils;
import org.sakaiproject.util.FormattedText;
public class MySearch extends BasePage {
private List<Person> results = new ArrayList<Person>();
private static final Logger log = Logger.getLogger(MySearch.class);
private WebMarkupContainer numSearchResultsContainer;
private Label numSearchResults;
private WebMarkupContainer resultsContainer;
private AjaxButton clearButton;
private TextField<String> sbiInterestField;
private TextField<String> sbnNameField;
public MySearch() {
log.debug("MySearch()");
disableLink(searchLink);
//setup model to store the actions in the modal windows
final FriendAction friendActionModel = new FriendAction();
//get current user info
final String currentUserUuid = sakaiProxy.getCurrentUserId();
final String currentUserType = sakaiProxy.getUserType(currentUserUuid);
/*
*
* SEARCH BY NAME FORM
*
*/
//heading
Label sbnHeading = new Label("sbnHeading", new ResourceModel("heading.search.byname"));
add(sbnHeading);
//setup form
StringModel sbnStringModel = new StringModel();
Form<StringModel> sbnForm = new Form<StringModel>("sbnForm", new Model<StringModel>(sbnStringModel));
sbnForm.setOutputMarkupId(true);
//search field
sbnForm.add(new Label("sbnNameLabel", new ResourceModel("text.search.byname")));
sbnNameField = new TextField<String>("searchName", new PropertyModel<String>(sbnStringModel, "string"));
sbnNameField.setRequired(true);
sbnNameField.setOutputMarkupId(true);
sbnForm.add(sbnNameField);
sbnForm.add(new IconWithClueTip("sbnNameToolTip", ProfileConstants.INFO_IMAGE, new ResourceModel("text.search.byname.tooltip")));
/*
*
* SEARCH BY INTEREST FORM
*
*/
//heading
Label sbiHeading = new Label("sbiHeading", new ResourceModel("heading.search.byinterest"));
add(sbiHeading);
//setup form
StringModel sbiStringModel = new StringModel();
Form<StringModel> sbiForm = new Form<StringModel>("sbiForm", new Model<StringModel>(sbiStringModel));
sbiForm.setOutputMarkupId(true);
//search field
sbiForm.add(new Label("sbiInterestLabel", new ResourceModel("text.search.byinterest")));
sbiInterestField = new TextField<String>("searchInterest", new PropertyModel<String>(sbiStringModel, "string"));
sbiInterestField.setRequired(true);
sbiInterestField.setOutputMarkupId(true);
sbiForm.add(sbiInterestField);
sbiForm.add(new IconWithClueTip("sbiInterestToolTip", ProfileConstants.INFO_IMAGE, new ResourceModel("text.search.byinterest.tooltip")));
/*
*
* RESULTS
*
*/
//search results label/container
numSearchResultsContainer = new WebMarkupContainer("numSearchResultsContainer");
numSearchResultsContainer.setOutputMarkupPlaceholderTag(true);
numSearchResults = new Label("numSearchResults");
numSearchResults.setOutputMarkupId(true);
numSearchResults.setEscapeModelStrings(false);
numSearchResultsContainer.add(numSearchResults);
//clear button
Form<Void> clearResultsForm = new Form<Void>("clearResults");
clearResultsForm.setOutputMarkupPlaceholderTag(true);
clearButton = new AjaxButton("clearButton", clearResultsForm) {
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
//clear the fields, hide self, then repaint
sbnNameField.clearInput();
sbnNameField.updateModel();
sbiInterestField.clearInput();
sbiInterestField.updateModel();
numSearchResultsContainer.setVisible(false);
resultsContainer.setVisible(false);
clearButton.setVisible(false);
target.addComponent(sbnNameField);
target.addComponent(sbiInterestField);
target.addComponent(numSearchResultsContainer);
target.addComponent(resultsContainer);
target.addComponent(this);
}
};
clearButton.setOutputMarkupPlaceholderTag(true);
clearButton.setVisible(false); //invisible until we have something to clear
clearButton.setModel(new ResourceModel("button.search.clear"));
clearResultsForm.add(clearButton);
numSearchResultsContainer.add(clearResultsForm);
add(numSearchResultsContainer);
// model to wrap search results
LoadableDetachableModel<List<Person>> resultsModel = new LoadableDetachableModel<List<Person>>(){
private static final long serialVersionUID = 1L;
protected List<Person> load() {
return results;
}
};
//container which wraps list
resultsContainer = new WebMarkupContainer("searchResultsContainer");
resultsContainer.setOutputMarkupPlaceholderTag(true);
resultsContainer.setVisible(false); //hide initially
//connection window
final ModalWindow connectionWindow = new ModalWindow("connectionWindow");
//search results
final PageableListView<Person> resultsListView = new PageableListView<Person>("searchResults",
resultsModel, sakaiProxy.getMaxSearchResultsPerPage()) {
private static final long serialVersionUID = 1L;
protected void populateItem(final ListItem<Person> item) {
Person person = (Person)item.getModelObject();
//get basic values
final String userUuid = person.getUuid();
final String displayName = person.getDisplayName();
final String userType = person.getType();
//get connection status
int connectionStatus = connectionsLogic.getConnectionStatus(currentUserUuid, userUuid);
boolean friend = (connectionStatus == ProfileConstants.CONNECTION_CONFIRMED) ? true : false;
//image wrapper, links to profile
Link<String> friendItem = new Link<String>("searchResultPhotoWrap") {
private static final long serialVersionUID = 1L;
public void onClick() {
setResponsePage(new ViewProfile(userUuid));
}
};
//image
friendItem.add(new ProfileImageRenderer("searchResultPhoto", person, ProfileConstants.PROFILE_IMAGE_THUMBNAIL, false));
item.add(friendItem);
//name and link to profile (if allowed or no link)
Link<String> profileLink = new Link<String>("searchResultProfileLink", new Model<String>(userUuid)) {
private static final long serialVersionUID = 1L;
public void onClick() {
//if user found themself, go to own profile, else show other profile
if(userUuid.equals(currentUserUuid)) {
setResponsePage(new MyProfile());
} else {
//gets userUuid of other user from the link's model
setResponsePage(new ViewProfile((String)getModelObject()));
}
}
};
profileLink.add(new Label("searchResultName", displayName));
item.add(profileLink);
//status component
ProfileStatusRenderer status = new ProfileStatusRenderer("searchResultStatus", person, "search-result-status-msg", "search-result-status-date");
status.setOutputMarkupId(true);
item.add(status);
/* ACTIONS */
boolean isFriendsListVisible = privacyLogic.isUserXFriendsListVisibleByUserY(userUuid, currentUserUuid, friend);
boolean isConnectionAllowed = sakaiProxy.isConnectionAllowedBetweenUserTypes(userType, currentUserType);
//ADD CONNECTION LINK
final WebMarkupContainer c1 = new WebMarkupContainer("connectionContainer");
c1.setOutputMarkupId(true);
if(!isConnectionAllowed){
//add blank components - TODO turn this into an EmptyLink component
AjaxLink<Void> emptyLink = new AjaxLink<Void>("connectionLink"){
private static final long serialVersionUID = 1L;
public void onClick(AjaxRequestTarget target) {}
};
emptyLink.add(new Label("connectionLabel"));
c1.add(emptyLink);
c1.setVisible(false);
} else {
//render the link
final Label connectionLabel = new Label("connectionLabel");
connectionLabel.setOutputMarkupId(true);
final AjaxLink<String> connectionLink = new AjaxLink<String>("connectionLink", new Model<String>(userUuid)) {
private static final long serialVersionUID = 1L;
public void onClick(AjaxRequestTarget target) {
//get this item, reinit some values and set content for modal
final String userUuid = (String)getModelObject();
connectionWindow.setContent(new AddFriend(connectionWindow.getContentId(), connectionWindow, friendActionModel, currentUserUuid, userUuid));
// connection modal window handler
connectionWindow.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
private static final long serialVersionUID = 1L;
public void onClose(AjaxRequestTarget target){
if(friendActionModel.isRequested()) {
connectionLabel.setDefaultModel(new ResourceModel("text.friend.requested"));
add(new AttributeModifier("class", true, new Model<String>("instruction icon connection-request")));
setEnabled(false);
target.addComponent(c1);
}
}
});
//in preparation for the window being closed, update the text. this will only
//be put into effect if its a successful model update from the window close
//connectionLabel.setModel(new ResourceModel("text.friend.requested"));
//this.add(new AttributeModifier("class", true, new Model("instruction")));
//this.setEnabled(false);
//friendActionModel.setUpdateThisComponentOnSuccess(this);
connectionWindow.show(target);
target.appendJavascript("fixWindowVertical();");
}
};
connectionLink.add(connectionLabel);
//setup 'add connection' link
if(StringUtils.equals(userUuid, currentUserUuid)) {
connectionLabel.setDefaultModel(new ResourceModel("text.friend.self"));
connectionLink.add(new AttributeModifier("class", true, new Model<String>("instruction icon profile")));
connectionLink.setEnabled(false);
} else if(friend) {
connectionLabel.setDefaultModel(new ResourceModel("text.friend.confirmed"));
connectionLink.add(new AttributeModifier("class", true, new Model<String>("instruction icon connection-confirmed")));
connectionLink.setEnabled(false);
} else if (connectionStatus == ProfileConstants.CONNECTION_REQUESTED) {
connectionLabel.setDefaultModel(new ResourceModel("text.friend.requested"));
connectionLink.add(new AttributeModifier("class", true, new Model<String>("instruction icon connection-request")));
connectionLink.setEnabled(false);
} else if (connectionStatus == ProfileConstants.CONNECTION_INCOMING) {
connectionLabel.setDefaultModel(new ResourceModel("text.friend.pending"));
connectionLink.add(new AttributeModifier("class", true, new Model<String>("instruction icon connection-request")));
connectionLink.setEnabled(false);
} else {
connectionLabel.setDefaultModel(new ResourceModel("link.friend.add"));
}
connectionLink.setOutputMarkupId(true);
c1.add(connectionLink);
}
item.add(c1);
//VIEW FRIENDS LINK
WebMarkupContainer c2 = new WebMarkupContainer("viewFriendsContainer");
c2.setOutputMarkupId(true);
final AjaxLink<String> viewFriendsLink = new AjaxLink<String>("viewFriendsLink") {
private static final long serialVersionUID = 1L;
public void onClick(AjaxRequestTarget target) {
//if user found themself, go to MyFriends, else, ViewFriends
if(userUuid.equals(currentUserUuid)) {
setResponsePage(new MyFriends());
} else {
setResponsePage(new ViewFriends(userUuid));
}
}
};
final Label viewFriendsLabel = new Label("viewFriendsLabel", new ResourceModel("link.view.friends"));
viewFriendsLink.add(viewFriendsLabel);
//hide if not allowed
if(!isFriendsListVisible) {
viewFriendsLink.setEnabled(false);
c2.setVisible(false);
}
viewFriendsLink.setOutputMarkupId(true);
c2.add(viewFriendsLink);
item.add(c2);
}
};
resultsContainer.add(resultsListView);
final PagingNavigator searchResultsNavigator = new PagingNavigator("searchResultsNavigator", resultsListView);
searchResultsNavigator.setOutputMarkupId(true);
searchResultsNavigator.setVisible(false);
resultsContainer.add(searchResultsNavigator);
add(connectionWindow);
//add results container
add(resultsContainer);
/*
*
* SEARCH BY NAME SUBMIT
*
*/
IndicatingAjaxButton sbnSubmitButton = new IndicatingAjaxButton("sbnSubmit", sbnForm) {
private static final long serialVersionUID = 1L;
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
if(target != null) {
//get the model and text entered
StringModel stringModel = (StringModel) form.getModelObject();
String searchText = ProfileUtils.stripHtml(stringModel.getString());
log.debug("MySearch() search.getSearchName(): " + searchText);
if(StringUtils.isBlank(searchText)){
return;
}
//clear the interest search field
sbiInterestField.clearInput();
sbiInterestField.updateModel();
//search both UDP and SakaiPerson for matches.
results = new ArrayList<Person>(profileLogic.findUsersByNameOrEmail(searchText));
Collections.sort(results);
int numResults = results.size();
int maxResults = sakaiProxy.getMaxSearchResults();
int maxResultsPerPage = sakaiProxy.getMaxSearchResultsPerPage();
//show the label wrapper
numSearchResultsContainer.setVisible(true);
//text
if(numResults == 0) {
numSearchResults.setDefaultModel(new StringResourceModel("text.search.byname.no.results", null, new Object[]{ searchText } ));
resultsContainer.setVisible(false);
clearButton.setVisible(false);
searchResultsNavigator.setVisible(false);
} else if (numResults == 1) {
numSearchResults.setDefaultModel(new StringResourceModel("text.search.byname.one.result", null, new Object[]{ searchText } ));
resultsContainer.setVisible(true);
clearButton.setVisible(true);
searchResultsNavigator.setVisible(false);
} else if (numResults == maxResults) {
numSearchResults.setDefaultModel(new StringResourceModel("text.search.toomany.results", null, new Object[]{ searchText, maxResults, maxResults } ));
resultsContainer.setVisible(true);
clearButton.setVisible(true);
searchResultsNavigator.setVisible(true);
} else if (numResults > maxResultsPerPage) {
numSearchResults.setDefaultModel(new StringResourceModel("text.search.byname.paged.results", null, new Object[]{ numResults, resultsListView.getViewSize(), searchText } ));
resultsContainer.setVisible(true);
clearButton.setVisible(true);
searchResultsNavigator.setVisible(true);
} else {
numSearchResults.setDefaultModel(new StringResourceModel("text.search.byname.all.results", null, new Object[]{ numResults, searchText } ));
resultsContainer.setVisible(true);
clearButton.setVisible(true);
searchResultsNavigator.setVisible(false);
}
//post view event
sakaiProxy.postEvent(ProfileConstants.EVENT_SEARCH_BY_NAME, "/profile/"+currentUserUuid, false);
//repaint components
target.addComponent(sbiInterestField);
target.addComponent(clearButton);
target.addComponent(numSearchResultsContainer);
target.addComponent(resultsContainer);
target.appendJavascript("setMainFrameHeight(window.name);");
}
}
};
sbnSubmitButton.setModel(new ResourceModel("button.search.byname"));
sbnForm.add(sbnSubmitButton);
add(sbnForm);
/*
*
* SEARCH BY INTEREST SUBMIT
*
*/
IndicatingAjaxButton sbiSubmitButton = new IndicatingAjaxButton("sbiSubmit", sbiForm) {
private static final long serialVersionUID = 1L;
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
if(target != null) {
//get the model and text entered
StringModel stringModel = (StringModel) form.getModelObject();
String searchText = ProfileUtils.stripHtml(stringModel.getString());
log.debug("MySearch() search.getSearchInterest(): " + searchText);
if(StringUtils.isBlank(searchText)){
return;
}
//clear the name search field
sbnNameField.clearInput();
sbnNameField.updateModel();
//search SakaiPerson for matches
results = new ArrayList<Person>(profileLogic.findUsersByInterest(searchText));
Collections.sort(results);
int numResults = results.size();
int maxResults = sakaiProxy.getMaxSearchResults();
int maxResultsPerPage = sakaiProxy.getMaxSearchResultsPerPage();
//show the label wrapper
numSearchResultsContainer.setVisible(true);
//text
if(numResults == 0) {
numSearchResults.setDefaultModel(new StringResourceModel("text.search.byinterest.no.results", null, new Object[]{ searchText } ));
resultsContainer.setVisible(false);
clearButton.setVisible(false);
searchResultsNavigator.setVisible(false);
} else if (numResults == 1) {
numSearchResults.setDefaultModel(new StringResourceModel("text.search.byinterest.one.result", null, new Object[]{ searchText } ));
resultsContainer.setVisible(true);
clearButton.setVisible(true);
searchResultsNavigator.setVisible(false);
} else if (numResults == maxResults) {
numSearchResults.setDefaultModel(new StringResourceModel("text.search.toomany.results", null, new Object[]{ searchText, maxResults, maxResults } ));
resultsContainer.setVisible(true);
clearButton.setVisible(true);
searchResultsNavigator.setVisible(true);
} else if (numResults > maxResultsPerPage) {
numSearchResults.setDefaultModel(new StringResourceModel("text.search.byinterest.paged.results", null, new Object[]{ numResults, resultsListView.getViewSize(), searchText } ));
resultsContainer.setVisible(true);
clearButton.setVisible(true);
searchResultsNavigator.setVisible(true);
} else {
numSearchResults.setDefaultModel(new StringResourceModel("text.search.byinterest.all.results", null, new Object[]{ numResults, searchText } ));
resultsContainer.setVisible(true);
clearButton.setVisible(true);
searchResultsNavigator.setVisible(false);
}
//post view event
sakaiProxy.postEvent(ProfileConstants.EVENT_SEARCH_BY_INTEREST, "/profile/"+currentUserUuid, false);
//repaint components
target.addComponent(sbnNameField);
target.addComponent(clearButton);
target.addComponent(numSearchResultsContainer);
target.addComponent(resultsContainer);
target.appendJavascript("setMainFrameHeight(window.name);");
}
}
};
sbiSubmitButton.setModel(new ResourceModel("button.search.byinterest"));
sbiForm.add(sbiSubmitButton);
add(sbiForm);
}
}