package com.eduworks.russel.ui.client.handler; import java.util.Vector; import com.eduworks.gwt.client.model.Record; import com.eduworks.gwt.client.model.StatusRecord; import com.eduworks.gwt.client.net.callback.ESBCallback; import com.eduworks.gwt.client.net.callback.EventCallback; import com.eduworks.gwt.client.net.packet.AjaxPacket; import com.eduworks.gwt.client.net.packet.ESBPacket; import com.eduworks.gwt.client.pagebuilder.PageAssembler; import com.eduworks.gwt.client.pagebuilder.screen.ScreenTemplate; import com.eduworks.russel.ui.client.Russel; import com.eduworks.russel.ui.client.extractor.FLRResultExtractor; import com.eduworks.russel.ui.client.model.RUSSELFileRecord; import com.eduworks.russel.ui.client.net.RusselApi; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; public class SearchHandler { public static final String TYPE_RECENT = "recent"; public static final String TYPE_SEARCH = "search"; public static final String TYPE_PROJECT = "project"; public static final String TYPE_EDIT = "edit"; public static final String TYPE_PROJECT_ASSET = "projectAsset"; public static final String TYPE_ASSET = "asset"; public static final String TYPE_COLLECTION = "collection"; public static final String TYPE_LINK = "link"; public static final String SOURCE_LEARNING_REGISTRY = "Learning Registry"; public static final String SOURCE_RUSSEL = "RUSSEL"; private Vector<TileHandler> tileHandlers = new Vector<TileHandler>(); private boolean terminate = false; private boolean pendingSearch = false; private Timer runQuery; private int tileIndex; private String query = ""; private String searchType; private HTML noResults = null; private boolean tableResults = false; private Vector<String> pagingTokens = new Vector<String>(); private String lastQuery = ""; private ScreenTemplate screen; private String objectPanel; public static final String RESULTS_NONE = "<p>No Search Results Found.</p>"; protected Vector<RUSSELFileRecord> pendingEdits; /** * cleanQuery Prepares the provided search text for query * @param rawSearchText * @return String */ public static String cleanQuery(String rawSearchText) { rawSearchText = rawSearchText.trim(); if (rawSearchText.equalsIgnoreCase("-")||rawSearchText.equalsIgnoreCase("!")||rawSearchText.equalsIgnoreCase("*")||rawSearchText.equalsIgnoreCase("not")|| rawSearchText.equalsIgnoreCase("search...")||rawSearchText.equalsIgnoreCase("Enter search terms...")) rawSearchText = ""; String[] searchTerms = rawSearchText.split(" "); String fullSearch = ""; char operator = ' '; for (int i=0 ; i<searchTerms.length; i++) { if (searchTerms[i] != "") { operator = searchTerms[i].charAt(0); if (searchTerms[i].equalsIgnoreCase("AND")||searchTerms[i].equalsIgnoreCase("&&")|| searchTerms[i].equalsIgnoreCase("OR")||searchTerms[i].equalsIgnoreCase("||")|| searchTerms[i].equalsIgnoreCase("NOT")||searchTerms[i].equalsIgnoreCase("*")) { fullSearch += " "+searchTerms[i]; } else if (searchTerms[i].indexOf(":") != -1) { fullSearch += " "+searchTerms[i]; } else if (operator == '-'||operator == '+'||operator == '!'||operator == '|'||operator == '~'||operator == '='){ fullSearch += " "+operator+searchTerms[i].substring(1); } else { fullSearch += " "+searchTerms[i]; } } } return fullSearch.trim(); } public SearchHandler(ScreenTemplate screen, boolean tableResults) { this.tableResults = tableResults; this.screen = screen; runQuery = new Timer() { @Override public void run() { pendingSearch = false; final ESBPacket ap = new ESBPacket(); ESBPacket sortPack = new ESBPacket(); sortPack.put("field", RUSSELFileRecord.UPDATED_DATE); sortPack.put("order", "desc"); ap.put("sort", sortPack); ap.put("q", query); query = null; ap.put("rows", 100); if (lastQuery!=ap.getString("q")) pagingTokens.clear(); lastQuery = ap.getString("q"); ap.put("page", pagingTokens.size()+1); ap.put("fields", new RUSSELFileRecord().getFieldList()); RusselApi.search(ap, searchType, new ESBCallback<ESBPacket>() { public void onFailure(Throwable caught) { tileHandlers.clear(); generateRootPanel(null); StatusHandler.createMessage(StatusHandler.getSearchMessageError(query), StatusRecord.ALERT_ERROR); } public void onSuccess(final ESBPacket searchTermPacket) { tileHandlers.clear(); if (searchTermPacket.getObject("obj").containsKey("cursor")) pagingTokens.add(0, searchTermPacket.getObject("obj").getString("cursor")); else pagingTokens.add(0, "*"); generateRootPanel(searchTermPacket); } }); } }; } public ScreenTemplate getScreen() { return screen; } public Vector<RUSSELFileRecord> getSelected() { return pendingEdits; } public boolean isPendingSearch() { return pendingSearch; } public void generateRootPanel(ESBPacket searchTermPacket) { RootPanel rp = RootPanel.get(objectPanel); if (rp!=null) { rp.clear(); int childCount = rp.getElement().getChildCount(); int grabIndex = 0; for (int childIndex=0;childIndex<childCount-((searchType.equals(TYPE_PROJECT))?1:0);childIndex++) { Element removeCursor = null; while (((removeCursor= (Element) rp.getElement().getChild(grabIndex))!=null)&&removeCursor.getId().equals("r-newEntity")) grabIndex++; if (removeCursor!=null) rp.getElement().removeChild(removeCursor); } if (searchTermPacket!=null) buildThumbnails(objectPanel, tableResults, searchTermPacket); } } /** * buildTile0 Initiates a tile in the Alfresco results panel. * @param searchTermPacket ESBPacket Alfresco search results * @param index int Index in the search results for the tile to be created * @param objPanel String Name of target panel for the tile * @param td Element Container for the tile * @return TileHandler */ public TileHandler buildTile(final RUSSELFileRecord r, String searchType, String objPanel) { Vector<String> iDs = null; if (searchType.equals(TYPE_RECENT)) iDs = PageAssembler.inject(objPanel, "x", new HTML(Russel.htmlTemplates.getObjectPanelWidget().getText()), false); else if (searchType.equals(TYPE_ASSET)) iDs = PageAssembler.inject(objPanel, "x", new HTML(Russel.htmlTemplates.getEPSSAssetObjectPanelWidget().getText()), false); else if (searchType.equals(TYPE_COLLECTION) || searchType.equals(TYPE_SEARCH) || searchType.equals(SOURCE_LEARNING_REGISTRY) || searchType.equals(TYPE_LINK)) iDs = PageAssembler.inject(objPanel, "x", new HTML(Russel.htmlTemplates.getSearchPanelWidget().getText()), false); else if (searchType.equals(TYPE_PROJECT)) iDs = PageAssembler.inject(objPanel, "x", new HTML(Russel.htmlTemplates.getEPSSProjectObjectPanelWidget().getText()), false); else if (searchType.equals(TYPE_PROJECT_ASSET)) iDs = PageAssembler.inject(objPanel, "x", new HTML(Russel.htmlTemplates.getEPSSNoteAssetObjectWidget().getText()), false); String idPrefix = iDs.firstElement().substring(0, iDs.firstElement().indexOf("-")); TileHandler th = new TileHandler(this, idPrefix, searchType, r); tileHandlers.add(th); return th; } /** * toggleSelection Selects or deselects the given tile * @param id String ID of desired tile * @param record ESBPacket Information associated with the tile */ public void toggleSelection(final String id, final Record recordx) { RUSSELFileRecord record = (RUSSELFileRecord) recordx; if (pendingEdits.contains(record)) { pendingEdits.remove(record); getTile0(id).deselect(); ((Label)PageAssembler.elementToWidget(id + "State", PageAssembler.LABEL)).removeStyleName("active"); ((Label)PageAssembler.elementToWidget(id + "Select", PageAssembler.LABEL)).removeStyleName("active"); } else { pendingEdits.add(record); getTile0(id).select(); ((Label)PageAssembler.elementToWidget(id + "State", PageAssembler.LABEL)).addStyleName("active"); ((Label)PageAssembler.elementToWidget(id + "Select", PageAssembler.LABEL)).addStyleName("active"); } if (pendingEdits.size()==0) { ((Anchor)PageAssembler.elementToWidget("r-objectEditSelected", PageAssembler.A)).removeStyleName("blue"); ((Anchor)PageAssembler.elementToWidget("r-objectEditSelected", PageAssembler.A)).addStyleName("white"); } else { ((Anchor)PageAssembler.elementToWidget("r-objectEditSelected", PageAssembler.A)).addStyleName("blue"); ((Anchor)PageAssembler.elementToWidget("r-objectEditSelected", PageAssembler.A)).removeStyleName("white"); } } /** * buildThumbnails Builds all of the tiles for the items in the search results * @param objPanel String Name of target panel for the tiles * @param searchTermPacket Adl3DRPacket 3DR search results */ public void buildThumbnails(String objPanel, boolean table, AjaxPacket searchTermPacket) { if (searchTermPacket != null) { RootPanel rp = RootPanel.get(objPanel); if (rp!=null) { tileIndex = 0; if (noResults!=null) rp.remove(noResults); Element td = null; if (searchTermPacket.containsKey("obj")) { JSONObject jo = searchTermPacket.getObject("obj").isObject(); if ((jo.containsKey("items")&&jo.get("items").isArray().size()==0) || (jo.containsKey("hits")&&jo.get("hits").isObject().get("hits").isArray().size()==0)) { rp.getElement().setAttribute("style", "text-align:center"); noResults = new HTML(RESULTS_NONE); rp.add(noResults); } else rp.getElement().setAttribute("style", ""); if (searchType.equals(SOURCE_LEARNING_REGISTRY)) { JSONArray ja = searchTermPacket.getObject("obj").get("hits").isObject().get("hits").isArray(); if (ja.size()==0) return; RUSSELFileRecord[] fileSet = FLRResultExtractor.walkBasicSearch(ja); for (int x=0;x<fileSet.length;x++) if (table) { if (x % 2 == 0) { td = DOM.createTD(); td.setId(x +"-" + rp.getElement().getId()); rp.getElement().appendChild(td); } buildTile(fileSet[x], searchType, td.getId()).fillTile(null); } else { buildTile(fileSet[x], searchType, objPanel).fillTile(null); } } else { for (int x=0;x<searchTermPacket.getObject("obj").get("items").isArray().size();x++) { if (table) { if (x % 2 == 0) { td = DOM.createTD(); td.setId(x +"-" + rp.getElement().getId()); rp.getElement().appendChild(td); } buildTile(new RUSSELFileRecord(new ESBPacket(searchTermPacket.getObject("obj").isObject().get("items").isArray().get(x).isObject())), searchType, td.getId()); } else { buildTile(new RUSSELFileRecord(new ESBPacket(searchTermPacket.getObject("obj").isObject().get("items").isArray().get(x).isObject())), searchType, objPanel); } } processCallbacks(); } } } } } /** * stop Sets terminate global to true */ public void stop() { terminate = true; } /** * selectAll Sets all tiles to selected state */ public void selectAll() { TileHandler tile = null; for (int i = 0; i<tileHandlers.size(); i++) { tile = tileHandlers.get(i); if (!tile.getSelectState()) { toggleSelection(tile.getIdPrefix(), tile.getSearchRecord()); } } } /** * selectNone Sets all tiles to deselected state */ public void selectNone() { TileHandler tile = null; for (int i = 0; i<tileHandlers.size(); i++) { tile = tileHandlers.get(i); if (tile.getSelectState()) { toggleSelection(tile.getIdPrefix(), tile.getSearchRecord()); } } } /** * getTile0 Retrieves the tile handler for the given tile id. * @param id String Desired tile id * @return TileHandler */ private TileHandler getTile0(String id) { TileHandler tile = null; for (int i = 0; i<tileHandlers.size(); i++) { if (id.contains(tileHandlers.get(i).getIdPrefix())) { tile = tileHandlers.get(i); } } return tile; } /** * forceSearch Schedules another custom query if there isn't already a pending search * @param customQuery String */ public void query(String query) { this.query = query; if (!pendingSearch) { pendingSearch = true; runQuery.schedule(1000); } else { runQuery.cancel(); runQuery.schedule(1000); } } public void previousPage() { if (pagingTokens.size()>0) pagingTokens.remove(0); if (pagingTokens.size()>0) pagingTokens.remove(0); } /** * processCallbacks Sets up tile information and handlers for each item in search results */ public void processCallbacks() { if ((!terminate) && ((tileHandlers.size()!=0&&tileIndex<tileHandlers.size()))) tileHandlers.get(tileIndex).fillTile(new EventCallback() { @Override public void onEvent(Event event) { tileIndex++; processCallbacks(); } }); } /** * hook Launches appropriate Alfresco query and assigns handlers for the response * @param seachbarID String Name of the search bar that informs the Alfresco query * @param objectPanel String Name of the target panel for Alfresco results * @param type String Name of the type of Alfresco search */ public void hookAndClear(String seachbarID, String objectPanel, String searchType) { this.objectPanel = objectPanel; this.searchType = searchType; query = null; pendingEdits = new Vector<RUSSELFileRecord>(); PageAssembler.removeHandler(seachbarID); PageAssembler.removeHandler(objectPanel); generateRootPanel(null); } }