IDEMPIERE-2050 Improvement to Menu Lookup. Add back support for search definition transaction code. Separate search definition into a separate tab so there's no performance penalty for menu. Added keyboard navigation ( up and down arrow ) for the search definition result list.
IDEMPIERE-2095 Menu Lookup return records from another client
This commit is contained in:
parent
fa3a9fa428
commit
543153c407
|
@ -54,6 +54,8 @@ public class DocumentSearchController implements EventListener<Event>{
|
|||
private static final String SEARCH_RESULT = "search.result";
|
||||
private static final String ON_SEARCH_DOCUMENTS = "onSearchDocuments";
|
||||
private Vlayout layout;
|
||||
private ArrayList<SearchResult> list;
|
||||
private int selected = -1;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -64,7 +66,8 @@ public class DocumentSearchController implements EventListener<Event>{
|
|||
public void create(Component parent) {
|
||||
layout = new Vlayout();
|
||||
layout.setStyle("padding: 3px;");
|
||||
layout.setWidth("200px");
|
||||
layout.setWidth("100%");
|
||||
layout.setVflex("true");
|
||||
|
||||
parent.appendChild(layout);
|
||||
|
||||
|
@ -77,6 +80,7 @@ public class DocumentSearchController implements EventListener<Event>{
|
|||
}
|
||||
|
||||
private void onSearchDocuments(String searchString) {
|
||||
list = new ArrayList<SearchResult>();
|
||||
if (Util.isEmpty(searchString)) {
|
||||
return;
|
||||
}
|
||||
|
@ -113,8 +117,8 @@ public class DocumentSearchController implements EventListener<Event>{
|
|||
|
||||
private List<SearchResult> doSearch(String searchString) {
|
||||
final MRole role = MRole.get(Env.getCtx(), Env.getAD_Role_ID(Env.getCtx()), Env.getAD_User_ID(Env.getCtx()), true);
|
||||
|
||||
List<SearchResult> list = new ArrayList<SearchResult>();
|
||||
|
||||
selected = -1;
|
||||
Query query = new Query(Env.getCtx(), I_AD_SearchDefinition.Table_Name, "", null);
|
||||
List<MSearchDefinition> definitions = query.setOnlyActiveRecords(true).list();
|
||||
for(MSearchDefinition msd : definitions) {
|
||||
|
@ -140,6 +144,7 @@ public class DocumentSearchController implements EventListener<Event>{
|
|||
} else {
|
||||
sql.append("WHERE UPPER(").append(column.getColumnName()).append(") LIKE UPPER(?)");
|
||||
}
|
||||
sql.append(" AND AD_Client_ID=@AD_Client_ID@ ");
|
||||
|
||||
// search for a Integer
|
||||
if (msd.getDataType().equals(MSearchDefinition.DATATYPE_INTEGER)) {
|
||||
|
@ -198,6 +203,13 @@ public class DocumentSearchController implements EventListener<Event>{
|
|||
String sql = builder.toString();
|
||||
if (!Util.isEmpty(extraWhereClase))
|
||||
sql = sql + extraWhereClase;
|
||||
//@@ is full text search operator for postgresql
|
||||
boolean hasFullTextOperator = sql.indexOf("@@") >= 0;
|
||||
if (hasFullTextOperator)
|
||||
sql = sql.replace("@@", "~!#$*");
|
||||
sql = Env.parseContext(Env.getCtx(), -1, sql, false, true);
|
||||
if (hasFullTextOperator)
|
||||
sql = sql.replace("~!#$*", "@@");
|
||||
pstmt = DB.prepareStatement(sql, (String)null);
|
||||
if (params.size() > 0)
|
||||
DB.setParameters(pstmt, params);
|
||||
|
@ -245,7 +257,7 @@ public class DocumentSearchController implements EventListener<Event>{
|
|||
AEnv.zoom(result.getWindowId(), query);
|
||||
}
|
||||
|
||||
private class SearchResult {
|
||||
public static class SearchResult {
|
||||
private String windowName;
|
||||
private int windowId;
|
||||
private String tableName;
|
||||
|
@ -362,4 +374,44 @@ public class DocumentSearchController implements EventListener<Event>{
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
public SearchResult selectPrior() {
|
||||
if (selected > 0) {
|
||||
selected--;
|
||||
SearchResult result = list.get(selected);
|
||||
List<Component> links = layout.getChildren();
|
||||
for(Component link : links) {
|
||||
if (link instanceof A) {
|
||||
A a = (A) link;
|
||||
if (result.getLabel().equals(a.getLabel())) {
|
||||
a.setSclass("document-search-current-link");
|
||||
} else if ("document-search-current-link".equals(a.getSclass())) {
|
||||
a.setSclass(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public SearchResult selectNext() {
|
||||
if (selected < (list.size()-1)) {
|
||||
selected++;
|
||||
SearchResult result = list.get(selected);
|
||||
List<Component> links = layout.getChildren();
|
||||
for(Component link : links) {
|
||||
if (link instanceof A) {
|
||||
A a = (A) link;
|
||||
if (result.getLabel().equals(a.getLabel())) {
|
||||
a.setSclass("document-search-current-link");
|
||||
} else if ("document-search-current-link".equals(a.getSclass())) {
|
||||
a.setSclass(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,17 @@
|
|||
*****************************************************************************/
|
||||
package org.adempiere.webui.apps;
|
||||
|
||||
import org.adempiere.webui.apps.DocumentSearchController.SearchResult;
|
||||
import org.adempiere.webui.component.Bandbox;
|
||||
import org.adempiere.webui.component.Tab;
|
||||
import org.adempiere.webui.component.Tabbox;
|
||||
import org.adempiere.webui.component.Tabpanel;
|
||||
import org.adempiere.webui.component.Tabpanels;
|
||||
import org.adempiere.webui.component.Tabs;
|
||||
import org.adempiere.webui.util.DocumentSearch;
|
||||
import org.compiere.util.Env;
|
||||
import org.compiere.util.Msg;
|
||||
import org.compiere.util.Util;
|
||||
import org.zkoss.zk.ui.Page;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
|
@ -23,8 +33,6 @@ import org.zkoss.zk.ui.event.KeyEvent;
|
|||
import org.zkoss.zk.ui.util.Clients;
|
||||
import org.zkoss.zul.Bandpopup;
|
||||
import org.zkoss.zul.Div;
|
||||
import org.zkoss.zul.Hlayout;
|
||||
import org.zkoss.zul.Separator;
|
||||
|
||||
/**
|
||||
* @author hengsin
|
||||
|
@ -40,6 +48,8 @@ public class GlobalSearch extends Div implements EventListener<Event> {
|
|||
|
||||
private static final String ON_SEARCH = "onSearch";
|
||||
|
||||
private static final String PREFIX_DOCUMENT_SEARCH = "/";
|
||||
|
||||
/**
|
||||
* generated serial id
|
||||
*/
|
||||
|
@ -50,6 +60,8 @@ public class GlobalSearch extends Div implements EventListener<Event> {
|
|||
private MenuSearchController menuController;
|
||||
private DocumentSearchController docController;
|
||||
|
||||
private Tabbox tabbox;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -61,26 +73,43 @@ public class GlobalSearch extends Div implements EventListener<Event> {
|
|||
|
||||
private void init() {
|
||||
bandbox = new Bandbox();
|
||||
bandbox.setSclass("global-search-box");
|
||||
appendChild(bandbox);
|
||||
bandbox.setWidth("100%");
|
||||
bandbox.setAutodrop(true);
|
||||
bandbox.addEventListener(Events.ON_CHANGING, this);
|
||||
bandbox.addEventListener(Events.ON_CHANGE, this);
|
||||
bandbox.setCtrlKeys("#up#down");
|
||||
bandbox.addEventListener(Events.ON_CTRL_KEY, this);
|
||||
|
||||
Bandpopup popup = new Bandpopup();
|
||||
popup.setHeight("600px");
|
||||
popup.setHeight("500px");
|
||||
bandbox.appendChild(popup);
|
||||
|
||||
Hlayout hlayout = new Hlayout();
|
||||
popup.appendChild(hlayout);
|
||||
menuController.create(hlayout);
|
||||
tabbox = new Tabbox();
|
||||
tabbox.setVflex("true");
|
||||
tabbox.addEventListener(Events.ON_SELECT, this);
|
||||
Tabs tabs = new Tabs();
|
||||
tabbox.appendChild(tabs);
|
||||
Tab tab = new Tab();
|
||||
tab.setLabel(Util.cleanAmp(Msg.getMsg(Env.getCtx(),"Menu")));
|
||||
tabs.appendChild(tab);
|
||||
Tabpanels tabPanels = new Tabpanels();
|
||||
tabbox.appendChild(tabPanels);
|
||||
Tabpanel tabPanel = new Tabpanel();
|
||||
tabPanel.setVflex("true");
|
||||
tabPanel.setSclass("global-search-tabpanel");
|
||||
tabPanels.appendChild(tabPanel);
|
||||
popup.appendChild(tabbox);
|
||||
menuController.create(tabPanel);
|
||||
|
||||
Separator separator = new Separator();
|
||||
separator.setHflex("0");
|
||||
separator.setOrient("vertical");
|
||||
hlayout.appendChild(separator);
|
||||
docController.create(hlayout);
|
||||
tab = new Tab();
|
||||
tab.setLabel(Util.cleanAmp(Msg.getMsg(Env.getCtx(),"Document")));
|
||||
tabs.appendChild(tab);
|
||||
tabPanel = new Tabpanel();
|
||||
tabPanel.setSclass("global-search-tabpanel");
|
||||
tabPanels.appendChild(tabPanel);
|
||||
docController.create(tabPanel);
|
||||
|
||||
addEventListener(ON_SEARCH, this);
|
||||
addEventListener(ON_CREATE_ECHO, this);
|
||||
|
@ -90,31 +119,50 @@ public class GlobalSearch extends Div implements EventListener<Event> {
|
|||
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
if (Events.ON_CHANGING.equals(event.getName())) {
|
||||
if (Events.ON_CHANGING.equals(event.getName())) {
|
||||
InputEvent inputEvent = (InputEvent) event;
|
||||
String value = inputEvent.getValue();
|
||||
Events.postEvent(ON_SEARCH, this, value);
|
||||
bandbox.setAttribute("last.onchanging", value);
|
||||
Events.postEvent(ON_SEARCH, this, value);
|
||||
} else if (Events.ON_CHANGE.equals(event.getName())) {
|
||||
bandbox.removeAttribute("last.onchanging");
|
||||
} else if (Events.ON_CTRL_KEY.equals(event.getName())) {
|
||||
KeyEvent ke = (KeyEvent) event;
|
||||
if (ke.getKeyCode() == KeyEvent.UP) {
|
||||
if (bandbox.getFirstChild().isVisible()) {
|
||||
MenuItem selected = menuController.selectPrior();
|
||||
if (selected != null) {
|
||||
bandbox.setText(selected.getLabel());
|
||||
if (tabbox.getSelectedIndex()==0) {
|
||||
MenuItem selected = menuController.selectPrior();
|
||||
if (selected != null) {
|
||||
bandbox.setText(selected.getLabel());
|
||||
}
|
||||
} else {
|
||||
SearchResult selected = docController.selectPrior();
|
||||
if (selected != null) {
|
||||
bandbox.setText(selected.getLabel());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ke.getKeyCode() == KeyEvent.DOWN) {
|
||||
if (bandbox.getFirstChild().isVisible()) {
|
||||
MenuItem selected = menuController.selectNext();
|
||||
if (selected != null && !"...".equals(selected.getType())) {
|
||||
bandbox.setText(selected.getLabel());
|
||||
if (tabbox.getSelectedIndex()==0) {
|
||||
MenuItem selected = menuController.selectNext();
|
||||
if (selected != null && !"...".equals(selected.getType())) {
|
||||
bandbox.setText(selected.getLabel());
|
||||
}
|
||||
} else {
|
||||
SearchResult selected = docController.selectNext();
|
||||
if (selected != null) {
|
||||
bandbox.setText(selected.getLabel());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (event.getName().equals(ON_SEARCH)) {
|
||||
String value = (String) event.getData();
|
||||
menuController.search(value);
|
||||
docController.search(value);
|
||||
if (tabbox.getSelectedIndex()==0)
|
||||
menuController.search(value);
|
||||
else
|
||||
docController.search(value);
|
||||
bandbox.focus();
|
||||
} else if (event.getName().equals(ON_CREATE_ECHO)) {
|
||||
StringBuilder script = new StringBuilder("jq('#")
|
||||
|
@ -132,11 +180,23 @@ public class GlobalSearch extends Div implements EventListener<Event> {
|
|||
Events.echoEvent(ON_POST_ENTER_KEY, this, null);
|
||||
} else if (event.getName().equals(ON_POST_ENTER_KEY)) {
|
||||
Clients.clearBusy(bandbox);
|
||||
if (menuController.onOk(bandbox)) {
|
||||
return;
|
||||
} else {
|
||||
docController.onOk(bandbox);
|
||||
if (bandbox.getValue() != null && bandbox.getValue().startsWith(PREFIX_DOCUMENT_SEARCH)) {
|
||||
DocumentSearch search = new DocumentSearch();
|
||||
if (search.openDocumentsByDocumentNo(bandbox.getValue().substring(1)))
|
||||
bandbox.setText(null);
|
||||
} else {
|
||||
if (tabbox.getSelectedIndex()==0) {
|
||||
menuController.onOk(bandbox);
|
||||
} else {
|
||||
docController.onOk(bandbox);
|
||||
}
|
||||
}
|
||||
} else if (event.getName().equals(Events.ON_SELECT)) {
|
||||
String value = (String) bandbox.getAttribute("last.onchanging");
|
||||
if (value == null) {
|
||||
value = bandbox.getValue();
|
||||
}
|
||||
Events.postEvent(ON_SEARCH, this, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ import java.util.ArrayList;
|
|||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.adempiere.webui.component.Label;
|
||||
import org.adempiere.webui.component.ListHead;
|
||||
import org.adempiere.webui.component.ListItem;
|
||||
import org.adempiere.webui.component.Listbox;
|
||||
|
@ -182,13 +181,11 @@ public class MenuSearchController implements EventListener<Event>{
|
|||
layout.setHeight("100%");
|
||||
parent.appendChild(layout);
|
||||
|
||||
Label label = new Label(Util.cleanAmp(Msg.getMsg(Env.getCtx(),"Menu")));
|
||||
label.setStyle("padding: 3px; font-weight: bold; display: block;");
|
||||
layout.appendChild(label);
|
||||
listbox = new Listbox();
|
||||
listbox.setEmptyMessage(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "FindZeroRecords")));
|
||||
listbox.setStyle("border: none");
|
||||
listbox.setWidth("500px");
|
||||
listbox.setWidth("100%");
|
||||
listbox.setVflex("true");
|
||||
layout.appendChild(listbox);
|
||||
listbox.setItemRenderer(new MenuItemRenderer());
|
||||
listbox.addEventListener(Events.ON_SELECT, this);
|
||||
|
@ -316,7 +313,7 @@ public class MenuSearchController implements EventListener<Event>{
|
|||
}
|
||||
|
||||
public void search(String value) {
|
||||
listbox.setVisible(false);
|
||||
listbox.setModel((ListModel)null);
|
||||
Events.echoEvent(ON_SEARCH_ECHO, layout, value);
|
||||
}
|
||||
|
||||
|
@ -330,7 +327,6 @@ public class MenuSearchController implements EventListener<Event>{
|
|||
newModel = (ListModelList<MenuItem>) subModel.getSubModel(null, -1);
|
||||
}
|
||||
updateListboxModel(newModel);
|
||||
listbox.setVisible(true);
|
||||
}
|
||||
|
||||
private void updateListboxModel(ListModelList<MenuItem> newModel) {
|
||||
|
|
|
@ -1676,6 +1676,15 @@ font-size: 0;
|
|||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.document-search-current-link {
|
||||
background-image:url(${c:encodeThemeURL('~./zul/img/tree/item-sel.gif')});
|
||||
}
|
||||
|
||||
.global-search-tabpanel {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
<%-- workaround for http://jira.idempiere.com/browse/IDEMPIERE-692 --%>
|
||||
.z-combobox-pp {
|
||||
max-height: 200px;
|
||||
|
|
Loading…
Reference in New Issue