0

Issue with ZK Checkbox?

asked 2012-09-11 09:42:40 +0800

sjoshi gravatar image sjoshi flag of India
3493 1 8
http://zkframeworkhint.bl...

Hi i have a macro Component for DualListBox which also contains the Checkbox..Something Like this...

<zk>
	<hlayout
		style="padding-left: 40px;padding-top:20px;padding-bottom:20px;"
		hflex="1" vflex="1">
		<separator />

		<listbox id="candidateLb" vflex="true" width="250px"
			multiple="true"   model="${arg.candidateModel}">
			<listhead>
				<listheader label="Default Column List"></listheader>

			</listhead>
			<template name="model" var="each">
				<listitem>
					<listcell label="${each}" />

				</listitem>
			</template>
		</listbox>

		<vbox spacing="10px">
			<image style="cursor:pointer" id="chooseAllBtn"
				src="/images/rightrightarrow_g.png" />
			<image style="cursor:pointer" id="chooseBtn"
				src="/images/rightarrow_g.png" />
			<image style="cursor:pointer" id="removeBtn"
				src="/images/leftarrow_g.png" />
			<image style="cursor:pointer" id="removeAllBtn"
				src="/images/leftleftarrow_g.png" />
		</vbox>
		<listbox id="chosenLb" vflex="true" width="250px"
			  model="${arg.chosenDataModel}" >
			<listhead>
				<listheader label="Selected Column List"></listheader>

			</listhead>
			<template name="model" var="each">
				<listitem>
				 
					<listcell label="${each.value}" >
					<separator orient="vertical"  />
					
                <b >    <checkbox checked="${each.checked}" /></b>
                    </listcell>
				</listitem>
			</template>
		</listbox>

		<vbox spacing="10px">
			<image style="cursor:pointer" id="topBtn"
				src="/images/upuparrow_g.png" />
			<image style="cursor:pointer" id="upBtn"
				src="/images/uparrow_g.png" />
			<image style="cursor:pointer" id="downBtn"
				src="/images/downarrow_g.png" />
			<image style="cursor:pointer" id="bottomBtn"
				src="/images/downdownarrow_g.png" />
		</vbox>

	</hlayout>
</zk>

My Problem is that when some one checked the CheckBox i want to call a method which will update some value...How can i do this.
thanks

delete flag offensive retag edit

31 Replies

Sort by ยป oldest newest

answered 2012-09-12 05:09:12 +0800

sjoshi gravatar image sjoshi flag of India
3493 1 8
http://zkframeworkhint.bl...

AnyOne Know How we can resolve this issue

link publish delete flag offensive edit

answered 2012-09-12 05:49:12 +0800

jj gravatar image jj
638 3

<checkbox ... forward="onCheck=onSomethingChecked" />

Then implement the onSomethingChecked(ForwardEvent evt) method in your composer

link publish delete flag offensive edit

answered 2012-09-12 07:00:40 +0800

sjoshi gravatar image sjoshi flag of India
3493 1 8
http://zkframeworkhint.bl...

Hi JJ ,
thanks for ur rely i tried it before but it not worked because this dual listbox is a Macro COmponent.
Do u have any other Solution

link publish delete flag offensive edit

answered 2012-09-12 08:42:51 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2012-09-12 08:43:24 +0800

Please read this article from Felipe about macro components and event handling. Hope it can helps.

best
Stephan

link publish delete flag offensive edit

answered 2012-09-12 09:04:03 +0800

sjoshi gravatar image sjoshi flag of India
3493 1 8
http://zkframeworkhint.bl...

Hi terrytornado,
Thanks for your answer ,my main issue is that i can not any static id to the Checkbox I want when anyone checked the checkbox i will update some value of my macro Java class do you know any work around for this.

link publish delete flag offensive edit

answered 2012-09-12 09:20:52 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2012-09-12 09:21:25 +0800

Please , separate the code (zul + java code + additionally configs) so that we can test it.

best
Stephan

link publish delete flag offensive edit

answered 2012-09-12 09:32:12 +0800

sjoshi gravatar image sjoshi flag of India
3493 1 8
http://zkframeworkhint.bl...

Hi terrytornado,
I separated ZUL and Java Code... Have Check...
I am Calling Macro Component Like this....

 <?component name="reorderListbox" macroURI="/macro_component_reorderlistbox.zul" extends="div" class="demo.listbox.dual_listbox.DualListbox"  ?>
<zk>

	<window apply="org.zkoss.bind.BindComposer" id="mainWindow"
		viewModel="@id('vm') @init('com.dual.listbox.DualListBoxVM')"
		width="100%" height="100%" >

		<button onClick="@command('showModelPopUp')"
			label="ReorderList">
		</button>

		<listbox model="@load(vm.model)" emptyMessage="Empty List"
			itemRenderer="@load(vm.itemRenderer)" id="test">

			<listhead children="@load(vm.headerList)">
				<template name="children" var="headerName">
					<listheader label="@load(headerName)"></listheader>
				</template>
			</listhead>


		</listbox>
		<window title="Reorder Listbox" id="queryWindow" height="80%"
			width="54%" mode="modal" position="center"
			visible="@load(vm.showModelWindow)" popup="true" apply="com.component.CheckBoxController">

			<reorderListbox candidateModel="@load(vm.availableList)"
				height="100%" width="100%" id="refreshListID"
				chosenDataModel="@load(vm.defaultSelected)">
			</reorderListbox>


			<button onClick="@command('updateListBox')" type="button"
				label="Save Order" id="updateButton" />
			<button onClick="@command('cancel')" type="button"
				label="Cancel" id="cancelButton" />



		</window>
	</window>
</zk>

This is My Macro Component ZUl Page...

<zk>
	<hlayout
		style="padding-left: 40px;padding-top:20px;padding-bottom:20px;"
		hflex="1" vflex="1" >
		<separator />

		<listbox id="candidateLb" vflex="true" width="250px"
			multiple="true"   model="${arg.candidateModel}">
			<listhead>
				<listheader label="Default Column List"></listheader>

			</listhead>
			<template name="model" var="each">
				<listitem>
					<listcell label="${each}"  />

				</listitem>
			</template>
		</listbox>

		<vbox spacing="10px">
			<image style="cursor:pointer" id="chooseAllBtn"
				src="/images/rightrightarrow_g.png" />
			<image style="cursor:pointer" id="chooseBtn"
				src="/images/rightarrow_g.png" />
			<image style="cursor:pointer" id="removeBtn"
				src="/images/leftarrow_g.png" />
			<image style="cursor:pointer" id="removeAllBtn"
				src="/images/leftleftarrow_g.png" />
		</vbox>
		<listbox id="chosenLb" vflex="true" width="250px"
			  model="${arg.chosenDataModel}" >
			<listhead>
				<listheader label="Selected Column List"></listheader>

			</listhead>
			<template name="model" var="each">
				<listitem>
				 
					<listcell label="${each.value}" >
					<separator orient="vertical"  />
					
                    <checkbox checked="${each.checked}"  />
                    </listcell>
				</listitem>
			</template>
		</listbox>

		<vbox spacing="10px">
			<image style="cursor:pointer" id="topBtn"
				src="/images/upuparrow_g.png" />
			<image style="cursor:pointer" id="upBtn"
				src="/images/uparrow_g.png" />
			<image style="cursor:pointer" id="downBtn"
				src="/images/downarrow_g.png" />
			<image style="cursor:pointer" id="bottomBtn"
				src="/images/downdownarrow_g.png" />
		</vbox>

	</hlayout>
</zk>

And this is my DualListBox.java Helper class ...

package demo.listbox.dual_listbox;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.zkoss.zhtml.Messagebox;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zk.ui.IdSpace;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Listbox;

public class DualListbox extends HtmlMacroComponent implements IdSpace {

	private static final long serialVersionUID = 1L;

	@Wire
	private Listbox candidateLb;

	@Wire
	private Listbox chosenLb;

	private ListModelList<String> candidataModel;

	private ListModelList<Data> chosenDataModel;

	public DualListbox() {
		compose();
		chosenLb.setModel(chosenDataModel = new ListModelList<Data>());
	}

	public ListModelList<Data> getChosenDataModel() {
		return chosenDataModel;
	}

	public void setChosenDataModel(ListModelList<Data> chosenDataModel) {
		chosenLb.setModel(chosenDataModel);
		this.chosenDataModel = chosenDataModel;
		for (Data value : chosenDataModel) {
			if (candidataModel.contains(value.getValue())) {
				candidataModel.remove(value.getValue());
			}
		}
		setCandidateModel(candidataModel);
	}

	public ListModelList<String> getCandidataModel() {
		return candidataModel;
	}

	public void setCandidateModel(ListModelList<String> candidataModel) {
		candidateLb.setModel(candidataModel);
		this.candidataModel = candidataModel;
	}
	
	

	@Listen("onClick = #chooseBtn")
	public void chooseItem() {
		Events.postEvent(new ChooseEvent(this, chooseOne()));
	}

	@Listen("onClick = #removeBtn")
	public void unchooseItem() {
		Events.postEvent(new ChooseEvent(this, unchooseOne()));
	}

	@Listen("onClick = #chooseAllBtn")
	public void chooseAllItem() {
		for (int i = 0, j = candidataModel.getSize(); i < j; i++) {
			Data data = new Data();
			data.setValue(candidataModel.getElementAt(i));
			data.setChecked(false);
			chosenDataModel.add(data);
		}
		candidataModel.clear();
	}

	@Listen("onClick = #removeAllBtn")
	public void unchooseAll() {
		for (int i = 0, j = chosenDataModel.getSize(); i < j; i++) {
			candidataModel.add(chosenDataModel.getElementAt(i).getValue());
		}
		chosenDataModel.clear();
	}

	@Listen("onClick = #topBtn")
	public void top() {
		int i = 0;
		Iterator<Data> iterator = new LinkedHashSet<Data>(chosenDataModel
				.getSelection()).iterator();
		while (iterator.hasNext()) {
			Data selectedItem = iterator.next();
			chosenDataModel.remove(selectedItem);
			chosenDataModel.add(i++, selectedItem);
			chosenDataModel.addToSelection(selectedItem);
		}
	}

	@Listen("onClick = #upBtn")
	public int up() {
		Set<Data> selected = chosenDataModel.getSelection();
		if (selected.isEmpty() || selected.size() > 1)
			return Messagebox.show("Only One Item can Shuffle Up");
		;
		int index = chosenDataModel.indexOf(selected.iterator().next());
		if (index == 0 || index < 0)
			return Messagebox.show("Only One Item can Shuffle Up");
		;
		Data selectedItem = chosenDataModel.get(index);
		chosenDataModel.remove(selectedItem);
		chosenDataModel.add(--index, selectedItem);
		chosenDataModel.addToSelection(selectedItem);
		return 0;

	}

	@Listen("onClick = #downBtn")
	public int down() {
		Set<Data> selected = chosenDataModel.getSelection();
		if (selected.isEmpty() || selected.size() > 1)
			return Messagebox.show("Only One Item can Shuffle Down");
		;
		int index = chosenDataModel.indexOf(selected.iterator().next());
		if (index == chosenDataModel.size() - 1 || index < 0 || index > 0)
			return Messagebox.show("Only One Item can Shuffle Down");
		Data selectedItem = chosenDataModel.get(index);
		chosenDataModel.remove(selectedItem);
		chosenDataModel.add(++index, selectedItem);
		chosenDataModel.addToSelection(selectedItem);
		return 0;
	}

	@Listen("onClick = #bottomBtn")
	public void bottom() {
		Iterator<Data> iterator = new LinkedHashSet<Data>(chosenDataModel
				.getSelection()).iterator();
		while (iterator.hasNext()) {
			Data selectedItem = iterator.next();
			chosenDataModel.remove(selectedItem);
			chosenDataModel.add(selectedItem);
			chosenDataModel.addToSelection(selectedItem);
		}
	}

	/**
	 * Set new candidate ListModelList.
	 * 
	 * @param candidate
	 *            is the data of candidate list model
	 */
	public void setModel(List<String> candidate) {
		candidateLb.setModel(this.candidataModel = new ListModelList<String>(
				candidate));
		chosenDataModel.clear();
	}

	/**
	 * @return current chosen data list
	 */
	public List<Data> getChosenDataList() {
		return new ArrayList<Data>(chosenDataModel);
	}

	private Set<String> chooseOne() {
		Set<String> set = candidataModel.getSelection();
		for (String selectedItem : set) {
			Data data = new Data();
			data.setChecked(false);
			data.setValue(selectedItem);
			chosenDataModel.add(data);
			candidataModel.remove(selectedItem);
		}
		return set;
	}

	private Set<String> unchooseOne() {
		Set<Data> set = chosenDataModel.getSelection();
		Set<String> set1 = new LinkedHashSet();
		for (Data selectedItem : set) {
			set1.add(selectedItem.getValue());
			candidataModel.add(selectedItem.getValue());
			chosenDataModel.remove(selectedItem);
		}
		return set1;
	}

	// Customized Event
	public class ChooseEvent extends Event {
		/**
         * 
         */
		private static final long serialVersionUID = -7334906383953342976L;

		public ChooseEvent(Component target, Set<String> data) {
			super("onChoose", target, data);
		}

	}

	public static class Data {
		String value;
		boolean checked;

		public String getValue() {
			return value;
		}

		public void setValue(String value) {
			this.value = value;
		}

		public boolean isChecked() {
			return checked;
		}

		public void setChecked(boolean checked) {
			this.checked = checked;
		}
	}

}

Do You need any thing else let me know...I will want to update the Data class(inner class) when user checked the Checkbox.
Thanks

link publish delete flag offensive edit

answered 2012-09-12 10:15:33 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

com.dual.listbox.DualListBoxVM is missing. Please post it.

link publish delete flag offensive edit

answered 2012-09-12 10:21:42 +0800

sjoshi gravatar image sjoshi flag of India
3493 1 8
http://zkframeworkhint.bl...

DualListBoxVM.java class

package com.dual.listbox;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listcell;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.ListitemRenderer;
import org.zkoss.zul.Window;

import com.component.ReorderListBox;

import demo.listbox.dual_listbox.DualListbox;
import demo.listbox.dual_listbox.DualListbox.Data;

public class DualListBoxVM  {

	private boolean showModelWindow = false;

	private Set _selected;

	public ListModelList<String> headerList;
	ReorderListBox rBox = new ReorderListBox();

	 

	@Wire("#queryWindow #refreshListID")
	DualListbox refreshListID;
	
	//DualListbox refreshListID;

	ListModelList<String> availableList = new ListModelList<String>();
	ListModelList<Data> defaultSelected = new ListModelList<Data>();

	@AfterCompose
	public void doAfterCompose(@ContextParam(ContextType.VIEW) Component view)
			throws Exception {
		Selectors.wireComponents(view, this, false);
		availableList.add("firstName");
		availableList.add("lastName");
		availableList.add("birthDate");
		availableList.add("homeCity");
		Data data = new Data();
		data.setChecked(true);
		data.setValue("firstName");
		defaultSelected.add(data);
		Data data1 = new Data();
		data1.setChecked(false);
		data1.setValue("lastName");
		defaultSelected.add(data1);
		 

		getSelected();
		getHeaderList();
	}

	public ListModel getModel() {
		ListModelList _model = null;
		if (_model == null) {
			_model = new ListModelList(getData());
		}

		return _model;
	}

	public List getData() {
		List _data = null;
		if (_data == null) {
			_data = new ArrayList();
			for (int i = 0; i < 10; i++) {
				_data.add(new DataBean("firstName_" + i, "lastName_" + i,
						"birthDate_" + i, "homeCity_" + i));
			}
		}
		return _data;
	}

	public ListModelList<String> getHeaderList() {
		return rBox.createHeaderList(_selected);
	}

	public void setHeaderList(ListModelList<String> headerList) {
		this.headerList = headerList;
	}

	// bind to chosenbox#selectedObjects
	public Set getSelected() {

		_selected = rBox.getdefaultSelected(_selected, defaultSelected);

		return _selected;
	}

	// bind to chosenbox#selectedObjects
	public void setSelected(Set selected) {
		_selected = rBox.getAllSelected(_selected, selected);
	}

	@Command("showModelPopUp")
	@NotifyChange("showModelWindow")
	public void showModelPopUp() {
		showModelWindow = true;

	}

	public ListitemRenderer getItemRenderer() {
		ListitemRenderer _rowRenderer = null;
		if (_rowRenderer == null) {
			_rowRenderer = new ListitemRenderer() {
				public void render(Listitem row, Object data, int index)
						throws Exception {
					final DataBean dataBean = (DataBean) data;
					if (_selected != null) {
						for (Object obj : _selected) {
							if ("firstName".equals(obj))
								new Listcell(dataBean.getFirstName())
										.setParent(row);
							else if ("lastName".equals(obj))
								new Listcell(dataBean.getLastName())
										.setParent(row);
							else if ("birthDate".equals(obj))
								new Listcell(dataBean.getBirthDate())
										.setParent(row);
							else if ("homeCity".equals(obj))
								new Listcell(dataBean.getHomeCity())
										.setParent(row);
						}
					}
				}

			};
		}
		return _rowRenderer;
	}

	StringBuilder _orderBy;

	@Command
	@NotifyChange( { "model", "headerList", "showModelWindow" })
	public void updateListBox(@ContextParam(ContextType.VIEW) Component view) {
		 
	 
	/*	ListModelList test = refreshListID.getChosenDataModel();
		for(Object obj : test){
			Data data = (Data)obj;
			System.out.println("data Value-->"+data.getValue()+"Data Checked-->"+data.isChecked());
		}
		System.out.println(test);*/
		DualListbox refreshListID = (DualListbox) view.getFellow("queryWindow")
		.getFellow("refreshListID");
		System.out.println("Hariom");
		refreshListID.getChosenDataList();
		/*List<Listitem> iteams = refreshListID.getItems();

		Set<Listitem> set1 = new LinkedHashSet(iteams);
		_orderBy = new StringBuilder();
		for (Listitem item : set1) {

			List<Component> com = item.getChildren();
			Checkbox chk = (Checkbox) com.get(0).getLastChild();
			Data data = item.getValue();
			if (chk.isChecked()) {
				_orderBy.append(data.getValue() + " ASC ");
				_orderBy.append(",");
			} else if (!chk.isChecked()) {
				_orderBy.append(data.getValue() + " DESC ");
				_orderBy.append(",");
			}

		}*/
	/*	Listbox refreshListID = (Listbox) view.getFellow("queryWindow")
				.getFellow("refreshListID").getFellow("chosenLb");*/
/*
		List<Listitem> iteams = test.getItems();

		Set<Listitem> set1 = new LinkedHashSet(iteams);
		_orderBy = new StringBuilder();
		for (Listitem item : set1) {

			List<Component> com = item.getChildren();
			Checkbox chk = (Checkbox) com.get(0).getLastChild();
			Data data = item.getValue();
			if (chk.isChecked()) {
				_orderBy.append(data.getValue() + " ASC ");
				_orderBy.append(",");
			} else if (!chk.isChecked()) {
				_orderBy.append(data.getValue() + " DESC ");
				_orderBy.append(",");
			}

		}
		System.out.println("Value--->" + _orderBy.toString());
		ListModelList<Data> header = (ListModelList) refreshListID.getModel();
		List dataList = new ArrayList();
		for (Data data : header) {
			dataList.add(data.getValue());
		}

		Set set = new LinkedHashSet(dataList);
		setSelected(set);
		getSelected();
		getModel();*/
		showModelWindow = false;
	}

	@Command
	@NotifyChange("showModelWindow")
	public void cancel() {
		showModelWindow = false;
	}

	@Command
	@NotifyChange("showModelWindow")
	public void cancelButton() {

		showModelWindow = false;
	}

	public class DataBean {
		public String firstName;
		public String lastName;
		public String birthDate;
		public String homeCity;

		public DataBean(String firstNameNew, String lastNamenew,
				String birthDatenew, String homeCitynew) {
			firstName = firstNameNew;
			lastName = lastNamenew;
			birthDate = birthDatenew;
			homeCity = homeCitynew;
		}

		public String getFirstName() {
			return firstName;
		}

		public void setFirstName(String firstName) {
			this.firstName = firstName;
		}

		public String getLastName() {
			return lastName;
		}

		public void setLastName(String lastName) {
			this.lastName = lastName;
		}

		public String getBirthDate() {
			return birthDate;
		}

		public void setBirthDate(String birthDate) {
			this.birthDate = birthDate;
		}

		public String getHomeCity() {
			return homeCity;
		}

		public void setHomeCity(String homeCity) {
			this.homeCity = homeCity;
		}

	}

	public boolean isShowModelWindow() {
		return showModelWindow;
	}

	public void setShowModelWindow(boolean showModelWindow) {
		this.showModelWindow = showModelWindow;
	}

	public ListModelList<String> getAvailableList() {
		return availableList;
	}

	public void setAvailableList(ListModelList<String> availableList) {
		this.availableList = availableList;
	}

	public ListModelList<Data> getDefaultSelected() {
		return defaultSelected;
	}

	public void setDefaultSelected(ListModelList<Data> defaultSelected) {
		this.defaultSelected = defaultSelected;
	}

	public DualListbox getRefreshListID() {
		return refreshListID;
	}

	public void setRefreshListID(DualListbox refreshListID) {
		this.refreshListID = refreshListID;
	}

}

And ReorderListBox.java

package com.component;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Listbox;

import demo.listbox.dual_listbox.DualListbox.Data;

public class ReorderListBox extends Listbox {

	public Set getdefaultSelected(Set _selected, ListModelList<Data> defaultCoulam) {
		if (_selected == null) {
			_selected = new LinkedHashSet();
			for (Data columnName : defaultCoulam) {
				_selected.add(columnName.getValue());
			}

		}
		return _selected;
	}

	public Set getAllSelected(Set _selected, Set selected) {
		if (_selected == null)
			_selected = new LinkedHashSet();
		_selected.clear();
		if (selected != null)
			_selected.addAll(selected);
		return _selected;

	}

	public ListModelList createHeaderList(Set _selected) {
		ListModelList<String> headerList = new ListModelList<String>();
		Object[] arr = _selected.toArray();
		for (Object obj : arr) {
			if(obj instanceof  Data){
			Data v = (Data) obj;
			headerList.add(v.getValue());
			}
			else{
				String v = (String) obj;
				headerList.add(v);
			}
		}
		return headerList;
	}

}

I have Implemented same thing you mentioned with Images Here Now i was trying to implement the sorting in Listbox having Millions of record with user choice. Then I struck in Checkbox Issue.
thanks

link publish delete flag offensive edit

answered 2012-09-12 10:55:11 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

java.lang.ClassNotFoundException: com.component.CheckBoxController

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2012-09-11 09:42:40 +0800

Seen: 918 times

Last updated: Oct 01 '12

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More