/*********************************************************************** * This file is part of iDempiere ERP Open Source * * http://www.idempiere.org * * * * Copyright (C) Contributors * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301, USA. * * * * Contributors: * * - Nicolas Micoud (TGI) * * - Alan Lescano * * - Norbert Bede * **********************************************************************/ package org.adempiere.webui.apps; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.adempiere.exceptions.AdempiereException; import org.adempiere.webui.component.Label; import org.adempiere.webui.component.ListHead; import org.adempiere.webui.component.ListItem; import org.adempiere.webui.component.Listbox; import org.adempiere.webui.panel.LabelsPanel; import org.adempiere.webui.theme.ThemeManager; import org.adempiere.webui.util.ZKUpdateUtil; import org.compiere.model.MLabel; import org.compiere.model.MLabelAssignment; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.Util; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.util.Clients; import org.zkoss.zul.ListModel; import org.zkoss.zul.ListModelList; import org.zkoss.zul.Listcell; import org.zkoss.zul.Listheader; import org.zkoss.zul.Listitem; import org.zkoss.zul.ListitemRenderer; import org.zkoss.zul.ListitemRendererExt; import org.zkoss.zul.Vlayout; /** * Controller for search on AD_Label* records. */ public class LabelsSearchController implements EventListener{ /** Event echo from {@link #onSelect(LabelItem)} **/ public static final String ON_POST_SELECT_LABELITEM_EVENT = "onPostSelectLabelitem"; /** Event echo to initiate search for a given input text **/ private static final String ON_SEARCH_ECHO_EVENT = "onSearchEcho"; /** TODO: not used, candidate for removal **/ private static final String ON_LOAD_MORE_EVENT = "onLoadMore"; /** parent of {@link #layout} **/ private Component parent; /** Listbox to display search result **/ private Listbox listbox; /** model for {@link #listbox} **/ private ListModelList model; /** main layout **/ private Vlayout layout; /** label window panel, provider for AD_Table_ID and Record_UU **/ private LabelsPanel labelsPanel; /** * Standard constructor * @param labelsPanel */ public LabelsSearchController(LabelsPanel labelsPanel) { this.labelsPanel = labelsPanel; } /** * Create the controller for the search field * @param parent */ public void create(Component parent) { this.parent = parent; layout = new Vlayout(); ZKUpdateUtil.setHeight(layout, "100%"); parent.appendChild(layout); listbox = new Listbox(); listbox.setItemRenderer(new LabelItemRenderer()); listbox.setStyle("border: none"); ZKUpdateUtil.setWidth(listbox, "100%"); ZKUpdateUtil.setVflex(listbox, "true"); layout.appendChild(listbox); listbox.addEventListener(Events.ON_SELECT, this); listbox.addEventListener(ON_POST_SELECT_LABELITEM_EVENT, this); ListHead listhead = new ListHead(); listbox.appendChild(listhead); Listheader listheader = new Listheader(); listhead.appendChild(listheader); listheader = new Listheader(); listheader.setAlign("center"); listheader.setValign("middle"); ZKUpdateUtil.setWidth(listheader, "30px"); listhead.appendChild(listheader); layout.addEventListener(ON_SEARCH_ECHO_EVENT, this); layout.addEventListener(ON_LOAD_MORE_EVENT, this); } @Override public void onEvent(Event event) throws Exception { if (event.getName().equals(ON_SEARCH_ECHO_EVENT)) { onSearchEcho((String) event.getData()); } else if (Events.ON_CLICK.equals(event.getName())) { if (event.getTarget() instanceof ListItem) { ListItem item = (ListItem) event.getTarget(); LabelItem labelItem = item.getValue(); onSelect(labelItem); } } } /** * Echo {@link #ON_SEARCH_ECHO_EVENT} to initiate search for value * @param value */ public void search(String value) { listbox.setModel((ListModel)null); Events.echoEvent(ON_SEARCH_ECHO_EVENT, layout, value); } /** * Handle {@link #ON_SEARCH_ECHO_EVENT} to execute search for a given text * @param value */ public void onSearchEcho(String value) { ListModelList newModel = null; if (Util.isEmpty(value)) { newModel = model; } else { newModel = new ListModelList(); boolean found = false; int currentIndex = 0; int foundIndex = 0; StringBuilder sql = new StringBuilder(); sql.append("SELECT "); sql.append(" AD_Label.AD_Label_ID, "); sql.append(" AD_Label.Name, "); sql.append(" COUNT(AD_LabelAssignment.AD_LabelAssignment_ID), "); sql.append(" CASE "); sql.append(" WHEN AD_Label.AD_LabelCategory_ID > 0 AND AD_LabelCategory.IsCanBeUsedInAllTables = 'N' "); sql.append(" AND AD_LabelCategoryTable.AD_Table_ID <> ").append(labelsPanel.getAD_Table_ID()).append(" THEN 'N' "); sql.append(" ELSE 'Y' "); sql.append(" END AS IsAllowed "); sql.append(" FROM AD_Label "); sql.append(" LEFT JOIN AD_LabelAssignment ON AD_LabelAssignment.AD_Label_ID = AD_Label.AD_Label_ID "); sql.append(" LEFT JOIN AD_LabelCategory ON AD_LabelCategory.AD_LabelCategory_ID = AD_LabelCategory.AD_LabelCategory_ID "); sql.append(" LEFT JOIN AD_LabelCategoryTable ON AD_LabelCategoryTable.AD_LabelCategory_ID = AD_LabelCategory.AD_LabelCategory_ID "); sql.append(" WHERE AD_Label.AD_Client_ID = ? AND LOWER(AD_Label.Name) LIKE LOWER(?) "); sql.append(" GROUP BY AD_Label.AD_Label_ID, AD_Label.Name, "); sql.append(" CASE "); sql.append(" WHEN AD_Label.AD_LabelCategory_ID > 0 AND AD_LabelCategory.IsCanBeUsedInAllTables = 'N' "); sql.append(" AND AD_LabelCategoryTable.AD_Table_ID <> ").append(labelsPanel.getAD_Table_ID()).append(" THEN 'N' "); sql.append(" ELSE 'Y' "); sql.append(" END "); sql.append(" ORDER BY COUNT(AD_LabelAssignment.AD_LabelAssignment_ID) DESC"); PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql.toString(), null); pstmt.setInt(1, Env.getAD_Client_ID(Env.getCtx())); pstmt.setString(2, "%" + value + "%"); rs = pstmt.executeQuery(); while (rs.next()) { LabelItem i = new LabelItem(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getBoolean(4)); newModel.add(i); if (rs.getString(2).toUpperCase().equals(value.toUpperCase())) { found = true; foundIndex = currentIndex; } currentIndex++; } } catch (SQLException e) { throw new AdempiereException(e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } if (!found) { LabelItem i = new LabelItem(0, value, 0, true); newModel.add(i); } listbox.setModel(newModel); listbox.setSelectedIndex(foundIndex); } } /** * Assign the selected label to the record. If doesn't exist, create the label. * @param item */ public void onSelect(LabelItem item) { if (item == null || !item.isAllowed()) return; MLabel label = null; if (item.getC_Label_ID() > 0) { label = new MLabel(Env.getCtx(), item.getC_Label_ID(), null); } else { // Try to find an existing label before creating a new one label = MLabel.getByName(Env.getCtx(), item.getLabel(), null); if (label == null) { label = new MLabel(Env.getCtx(), 0, null); } } if (label.get_ID() <= 0) { label.setAD_Org_ID(0); label.setName(item.getLabel()); label.saveEx(); } // Assign if (!MLabelAssignment.hasLabelAssignment(label.get_ID(), labelsPanel.getAD_Table_ID(), labelsPanel.getRecord_UU())) { MLabelAssignment assign = new MLabelAssignment(Env.getCtx(), 0, null); assign.setAD_Org_ID(label.getAD_Org_ID()); assign.setAD_Label_ID(label.get_ID()); assign.setAD_Table_ID(labelsPanel.getAD_Table_ID()); assign.setRecord_ID(labelsPanel.getRecord_ID()); assign.setRecord_UU(labelsPanel.getRecord_UU()); assign.saveEx(); } Events.echoEvent(ON_POST_SELECT_LABELITEM_EVENT, labelsPanel, item); Events.echoEvent(ON_POST_SELECT_LABELITEM_EVENT, parent.getParent().getParent(), item); } /** * Get the selected item in the search results * @return selected label or null */ public LabelItem getSelectedItem() { ListItem selected = listbox.getSelectedItem(); if (selected == null) return null; return selected.getValue(); } /** * Select the previous item in the search results * @return previous label or null */ public LabelItem selectPrior() { int i = listbox.getSelectedIndex(); if (i > 0) { listbox.setSelectedIndex(i-1); ListItem selected = listbox.getSelectedItem(); if (selected == null) return null; Clients.scrollIntoView(selected); LabelItem item = selected.getValue(); return item; } return null; } /** * Select the next item in the search results * @return next label or null */ public LabelItem selectNext() { int i = listbox.getSelectedIndex(); if (i < 0 && listbox.getItemCount() > 0) { listbox.setSelectedIndex(0); ListItem selected = listbox.getSelectedItem(); if (selected == null) return null; LabelItem item = selected.getValue(); return item; } else if (i+1 < listbox.getItemCount()) { listbox.setSelectedIndex(i+1); ListItem selected = listbox.getSelectedItem(); if (selected == null) return null; LabelItem item = selected.getValue(); if (item == null) return null; Clients.scrollIntoView(selected); return item; } return null; } /** * Search result item */ public class LabelItem { private String label; private int C_Label_ID; private int countUsed; private boolean isAllowed; public LabelItem(int C_Label_ID, String label, int countUsed, boolean isAllowed) { this.label = label; this.C_Label_ID = C_Label_ID; this.countUsed = countUsed; this.isAllowed = isAllowed; } public String getLabel() { return label; } public int getC_Label_ID() { return C_Label_ID; } public int getCountUsed() { return countUsed; } public boolean isAllowed() { return isAllowed; } } private class LabelItemRenderer implements ListitemRenderer, ListitemRendererExt { @Override public Listitem newListitem(org.zkoss.zul.Listbox listbox) { return new ListItem(); } @Override public Listcell newListcell(Listitem item) { return new Listcell(item.getLabel()); } @Override public int getControls() { return ListitemRendererExt.DETACH_ON_RENDER; } @Override public void render(Listitem item, LabelItem data, int index) throws Exception { Label labelName = new Label(data.getLabel()); labelName.setStyle("color: " + MLabel.calculateHexColor(data.getLabel())); Listcell cell = new Listcell(); cell.appendChild(labelName); if (data.getC_Label_ID() > 0) { Label labelCountUsed = new Label("(" + data.getCountUsed() + ")"); labelCountUsed.setStyle("color: #909090; margin-left: 4px;"); cell.appendChild(labelCountUsed); } if (!data.isAllowed()) item.setDisabled(true); item.appendChild(cell); item.setValue(data); item.addEventListener(Events.ON_CLICK, LabelsSearchController.this); Listcell cell2 = new Listcell(); if (data.getC_Label_ID() <= 0) { if (ThemeManager.isUseFontIconForImage()) cell2.setIconSclass("z-icon-New"); else cell2.setImage(ThemeManager.getThemeResource("images/New16.png")); } else { if (!data.isAllowed()) { if (ThemeManager.isUseFontIconForImage()) cell2.setIconSclass("z-icon-NotAllowed"); else cell2.setImage(ThemeManager.getThemeResource("images/Cancel16.png")); } } item.appendChild(cell2); } } }