Revision: 8044
Author: [email protected]
Date: Tue May 4 10:22:18 2010
Log: Adding Departments to Employees and updating the ExpenseTree so it
loads employees correctly. Open icon now turns to a loading icon while
loading.
http://code.google.com/p/google-web-toolkit/source/detail?r=8044
Added:
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/cellTreeLoading.gif
Modified:
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/list/client/impl/CellListImpl.java
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTree.css
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTree.java
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTreeNodeView.java
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseTree.java
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/Expenses.java
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Employee.java
=======================================
--- /dev/null
+++
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/cellTreeLoading.gif
Tue May 4 10:22:18 2010
@@ -0,0 +1,75 @@
+GIF89a ö ÿÿÿ ÌÔÔõ””é``Þ@@ØDDÙnnᢢëÜÜ÷¤¤ì$$Ó((Ó00Õ66Ö>>Øjj຺ð
+
+ÑrrâììúîîúÂÂòŠŠçPPÛ^^Þ¾¾ñÐÐô::× ÐŒŒçªªí\\Þ||äââø††æ Îhhàœœêffà¶¶ïFFÙ
+
+Ͱ°î––é Ð
Íèèùôôüxxã„„åööü‚‚娨íúúýüüýÀÀñÊÊóøøüÖÖö®®îððûÒÒõääøÞÞ÷ÎÎôÆÆò¼¼ñààøØØöòòûÚÚözzä´´ï²²ïLLÚRRÜZZÝbbßBBØ<<×ÄÄòvvã22Õêêú**ÔŽŽçXXÝ,,Ô
+
+Ñ ëNNÛ Ïˆˆæddß44ÖÈÈóÌÌôææù¸¸ð~~ä’’èžžëVVÜ èJJÚHHÚ""Ò¦¦ì Ï Î¬¬í Ìššê&&Ó Ï88×ttâ..Õ Íppâ
ÒTTÜllကå !ÿ NETSCAPE2.0 !þ Created
with ajaxload.info !ù
+ , € ‚ƒ„
+
+ #)-†
+
+$*.‚6:7
+
+
+%+/‚70=6ƒ
+†6 – Œ =?=‚ �...@?‚
+ ± ;E‚ ±7A>‚ ± B;‚ ±>CD‚ †;+ Fƒ & 03 8 <Ý„ !' 14
+,< Œ"P° á¡FŽ` !ù
+ , Œ€ ‚ƒ„
+
+; WX [] † < U Y-\$_&
+JOSH TJ^*\„G P›
+2
+
+ # ‚7ƒHKQ³ :6‚ L=ºFF‚'Mij ‚ NA³:bË I �...@Á ? R †/ D½‚924I ::/E` ÓƒA&V,Z JCaT T9Ij¬ ’ †®ƒ !ù
+ , ‰€ ‚ƒ„
+
+
+ i ^, † C K
+ jl
+8^ghQ CRk ƒ"dN<†h-P ‚c f m]‚, >·Jnj‚2H0·T.-‚
+43·
+5 GЄ`eC·6:ƒ f¿
+:=σG5 AT770 / 6
+...@c(CBA;@/܆F rø ¯Zµ@ !ù
+ , € ‚ƒ„
+
+?(
+ N!lG† 9 ' g[jNJ
+A#Hl F=B] O<ƒT&28†f_L;‚9V( H ‚J, · kW‚lf:· U‚olÇ T
+r‚ <b·JmK‚G(>·N*#‚F`8" p
+Aƒ/`9"0‚7ô q
+ E "T=36né F o)
+ !ù
+ , Œ€ ‚ƒ„
+
+ aoe
+& ?† +qe 4H 2
+D<
+ @33
+% ƒF8<;†J @�...@c e[l‚>8T·Bju‚aB7· K¼AÇ ³ 0·Cv^‚ ¿ ur ‚6b?Õ
+
+Y) ƒ3T 3ƒ+'s
+
+6F0:‚.nt ·n830ÂÖƒ‚ !ù
+ , ‰€ ‚ƒ„
+
+...@9(+ A † TA8cJ q
+>
+ `GT6:" VVAƒ6@>/†B4eb‚= oR ‚TD3 > h»²¿F^ ‚ ÆM'‚0F7¿BLd‚63Ó ]jlƒ7Û
+& NG† +TTc1SOJ†vwn\-Yr < A#i ΔÙñ«à @ !ù
+ , ˆ€ ‚ƒ„
+
+7=?;>;"0† :TD AB8Q"
+6 / 3 7 ;(i...@„0=:†G J ‚73¬ QfA²6 ‚D,<¼
+3
+eÁ„34
+‚ .À 1&‚2*^¼Z ‚ \ †<N|›‚Zk-xc Vz^8
+ Oyrv j{CÏe H`ÌX !ù
+ , ‹€ ‚ƒ„
+†7:F F6†ƒ63F bDD=
+&†: E; ƒA
+. TA>3‚#*N
D‚K$+® C9‚ \T®6Jc‚ -¾ : ¶ gY(®DZ ‚e u® ,A‚ KXq† Æ oPt2Q=FAl!
++ OjLM^
+a G 1 n...@ñÕÁa ;
=======================================
---
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/list/client/impl/CellListImpl.java
Tue May 4 08:08:32 2010
+++
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/list/client/impl/CellListImpl.java
Tue May 4 10:22:18 2010
@@ -53,6 +53,14 @@
private final List<T> data = new ArrayList<T>();
private int dataSize;
+
+ /**
+ * A boolean indicating whether or not the data size has ever been set.
If the
+ * data size has never been set, then we will always pass it along to the
+ * view.
+ */
+ private boolean dataSizeInitialized;
+
private Delegate<T> delegate;
private final PagingListView<T> listView;
private Pager<T> pager;
@@ -276,9 +284,10 @@
* @param size the overall size
*/
public void setDataSize(int size) {
- if (size == this.dataSize) {
+ if (dataSizeInitialized && size == this.dataSize) {
return;
}
+ dataSizeInitialized = true;
this.dataSize = size;
updateDataAndView();
onSizeChanged();
=======================================
---
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTree.css
Fri Apr 30 09:33:31 2010
+++
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTree.css
Tue May 4 10:22:18 2010
@@ -1,3 +1,8 @@
+.emptyMessage {
+ padding-left: 16px;
+ font-style: italic;
+}
+
.item {
padding: 4px 3px;
}
@@ -7,7 +12,6 @@
}
.openItem {
- font-weight: bold;
}
@sprite .selectedItem {
@@ -17,3 +21,8 @@
height: auto;
overflow: auto;
}
+
+.showMoreButton {
+ padding-left: 16px;
+ outline: none;
+}
=======================================
---
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTree.java
Fri Apr 30 09:33:31 2010
+++
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTree.java
Tue May 4 10:22:18 2010
@@ -38,11 +38,21 @@
*/
public class CellTree extends Composite implements HasAnimation {
+ /**
+ * The default number of children to show under a tree node.
+ */
+ private static final int DEFAULT_LIST_SIZE = 25;
+
/**
* Styles used by this widget.
*/
public static interface Style extends CssResource {
+ /**
+ * Applied to the empty message.
+ */
+ String emptyMessage();
+
/**
* Applied to tree items.
*/
@@ -62,6 +72,11 @@
* Applied to selected tree items.
*/
String selectedItem();
+
+ /**
+ * Applied to the show more button.
+ */
+ String showMoreButton();
}
/**
@@ -74,6 +89,11 @@
*/
ImageResource cellTreeClosedItem();
+ /**
+ * An image indicating that a node is loading.
+ */
+ ImageResource cellTreeLoading();
+
/**
* An image indicating an open branch.
*/
@@ -311,6 +331,11 @@
*/
private final String closedImageHtml;
+ /**
+ * The default number of children to display under each node.
+ */
+ private int defaultNodeSize = DEFAULT_LIST_SIZE;
+
/**
* The maximum width of the open and closed images.
*/
@@ -322,10 +347,9 @@
private boolean isAnimationEnabled;
/**
- * The message displayed while child nodes are loading.
+ * The HTML used to generate the loading image.
*/
- // TODO(jlabanca): I18N loading HTML, or remove the text.
- private String loadingHtml = "Loading...";
+ private final String loadingImageHtml;
/**
* The HTML used to generate the open image.
@@ -377,9 +401,12 @@
// Initialize the open and close images strings.
ImageResource treeOpen = resources.cellTreeOpenItem();
ImageResource treeClosed = resources.cellTreeClosedItem();
+ ImageResource treeLoading = resources.cellTreeLoading();
openImageHtml = getImageHtml(treeOpen);
closedImageHtml = getImageHtml(treeClosed);
- imageWidth = Math.max(treeOpen.getWidth(), treeClosed.getWidth());
+ loadingImageHtml = getImageHtml(treeLoading);
+ imageWidth = Math.max(Math.max(treeOpen.getWidth(),
treeClosed.getWidth()),
+ treeLoading.getWidth());
// We use one animation for the entire tree.
setAnimation(SlideAnimation.create());
@@ -406,13 +433,12 @@
}
/**
- * Get the HTML string that is displayed while nodes wait for their
children
- * to load.
+ * Get the default maximum number of children to display under each tree
node.
*
- * @return the loading HTML string
+ * @return the default node size
*/
- public String getLoadingHtml() {
- return loadingHtml;
+ public int getDefaultNodeSize() {
+ return defaultNodeSize;
}
public CellTreeViewModel getTreeViewModel() {
@@ -436,14 +462,10 @@
if (nodeView != null && nodeView != rootNode) {
if ("click".equals(event.getType())) {
// Open the node when the open image is clicked.
- Element showFewerElem = nodeView.getShowFewerElement();
Element showMoreElem = nodeView.getShowMoreElement();
if (nodeView.getImageElement().isOrHasChild(target)) {
nodeView.setOpen(!nodeView.isOpen());
return;
- } else if (showFewerElem != null &&
showFewerElem.isOrHasChild(target)) {
- nodeView.showFewer();
- return;
} else if (showMoreElem != null &&
showMoreElem.isOrHasChild(target)) {
nodeView.showMore();
return;
@@ -480,13 +502,15 @@
}
/**
- * Set the HTML string that will be displayed when a node is waiting for
its
- * child nodes to load.
+ * Set the default number of children to display beneath each child
node. If
+ * more nodes are available, a button will appear at the end of the list
+ * allowing the user to show more items. Changing this value will not
affect
+ * tree nodes that are already open.
*
- * @param loadingHtml the HTML string
+ * @param defaultNodeSize the max
*/
- public void setLoadingHtml(String loadingHtml) {
- this.loadingHtml = loadingHtml;
+ public void setDefaultNodeSize(int defaultNodeSize) {
+ this.defaultNodeSize = defaultNodeSize;
}
/**
@@ -504,6 +528,13 @@
int getImageWidth() {
return imageWidth;
}
+
+ /**
+ * @return the HTML to render the loading image.
+ */
+ String getLoadingImageHtml() {
+ return loadingImageHtml;
+ }
/**
* @return the HTML to render the open image.
=======================================
---
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTreeNodeView.java
Fri Apr 30 09:33:31 2010
+++
/branches/2.1/bikeshed/src/com/google/gwt/bikeshed/tree/client/CellTreeNodeView.java
Tue May 4 10:22:18 2010
@@ -22,6 +22,7 @@
import com.google.gwt.bikeshed.list.shared.Range;
import com.google.gwt.bikeshed.list.shared.SelectionModel;
import com.google.gwt.bikeshed.tree.client.CellTreeViewModel.NodeInfo;
+import com.google.gwt.dom.client.AnchorElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
@@ -42,11 +43,6 @@
*/
class CellTreeNodeView<T> extends UIObject {
- /**
- * The default number of children to show under a tree node.
- */
- private static final int DEFAULT_LIST_SIZE = 100;
-
/**
* The element used in place of an image when a node has no children.
*/
@@ -84,21 +80,23 @@
*/
private static class NodeListView<C> implements PagingListView<C> {
+ private final int defaultPageSize;
private final CellListImpl<C> impl;
private CellTreeNodeView<?> nodeView;
private Map<Object, CellTreeNodeView<?>> savedViews;
public NodeListView(final NodeInfo<C> nodeInfo,
- final CellTreeNodeView<?> nodeView) {
+ final CellTreeNodeView<?> nodeView, int pageSize) {
+ this.defaultPageSize = pageSize;
this.nodeView = nodeView;
final Cell<C> cell = nodeInfo.getCell();
- impl = new CellListImpl<C>(this, DEFAULT_LIST_SIZE,
+ impl = new CellListImpl<C>(this, pageSize,
nodeView.ensureChildContainer()) {
@Override
public void setData(List<C> values, int start) {
- showOrHide(nodeView.loadingMessageElem, false);
+ nodeView.updateImage(false);
// Ensure that we have a children array.
if (nodeView.children == null) {
@@ -157,7 +155,6 @@
child.nodeInfo = savedChild.nodeInfo;
child.nodeInfoLoaded = savedChild.nodeInfoLoaded;
child.open = savedChild.open;
- child.showFewerElem = savedChild.showFewerElem;
child.showMoreElem = savedChild.showMoreElem;
// Swap the node view in the child. We reuse the same
NodeListView
@@ -248,11 +245,14 @@
impl.setPager(new Pager<C>() {
public void onRangeOrSizeChanged(PagingListView<C> listView) {
// Assumes a page start of 0.
- showOrHide(nodeView.showMoreElem,
- impl.getDataSize() > impl.getPageSize());
- showOrHide(nodeView.showFewerElem,
- impl.getPageSize() > DEFAULT_LIST_SIZE);
- showOrHide(nodeView.emptyMessageElem, impl.getDataSize() == 0);
+ int dataSize = impl.getDataSize();
+ showOrHide(nodeView.showMoreElem, dataSize > impl.getPageSize());
+ if (dataSize == 0) {
+ showOrHide(nodeView.emptyMessageElem, true);
+ nodeView.updateImage(false);
+ } else {
+ showOrHide(nodeView.emptyMessageElem, false);
+ }
}
});
}
@@ -267,6 +267,10 @@
public int getDataSize() {
return impl.getDataSize();
}
+
+ public int getDefaultPageSize() {
+ return defaultPageSize;
+ }
public int getPageSize() {
return impl.getPageSize();
@@ -358,11 +362,6 @@
*/
private NodeListView<?> listView;
- /**
- * The element used when the children are loading.
- */
- private Element loadingMessageElem;
-
/**
* The info about children of this node.
*/
@@ -388,15 +387,10 @@
*/
private final NodeInfo<T> parentNodeInfo;
- /**
- * The element used to display less children.
- */
- private Element showFewerElem;
-
/**
* The element used to display more children.
*/
- private Element showMoreElem;
+ private AnchorElement showMoreElem;
/**
* The {...@link CellTree} that this node belongs to.
@@ -476,20 +470,23 @@
if (nodeInfo != null) {
// Add a loading message.
ensureChildContainer();
- showOrHide(loadingMessageElem, true);
- showOrHide(showFewerElem, false);
showOrHide(showMoreElem, false);
showOrHide(emptyMessageElem, false);
+ if (!isRootNode()) {
+ setStyleName(getCellParent(), tree.getStyle().openItem(), true);
+ }
ensureAnimationFrame().getStyle().setProperty("display", "");
+ updateImage(true);
onOpen(nodeInfo);
}
} else {
+ if (!isRootNode()) {
+ setStyleName(getCellParent(), tree.getStyle().openItem(), false);
+ }
cleanup();
tree.maybeAnimateTreeNode(this);
- }
-
- // Update the image.
- updateImage();
+ updateImage(false);
+ }
}
/**
@@ -583,33 +580,12 @@
* @param <C> the child data type of the node
*/
protected <C> void onOpen(final NodeInfo<C> nodeInfo) {
- NodeListView<C> view = new NodeListView<C>(nodeInfo, this);
+ NodeListView<C> view = new NodeListView<C>(nodeInfo, this,
+ tree.getDefaultNodeSize());
listView = view;
view.setSelectionModel(nodeInfo.getSelectionModel());
nodeInfo.setView(view);
}
-
- /**
- * Update the image based on the current state.
- */
- protected void updateImage() {
- // Early out if this is a root node.
- if (parentNode == null) {
- return;
- }
-
- // Replace the image element with a new one.
- String html = open ? tree.getOpenImageHtml() :
tree.getClosedImageHtml();
- if (nodeInfoLoaded && nodeInfo == null) {
- html = LEAF_IMAGE;
- }
- Element tmp = Document.get().createDivElement();
- tmp.setInnerHTML(html);
- Element imageElem = tmp.getFirstChildElement();
-
- Element oldImg = getImageElement();
- oldImg.getParentElement().replaceChild(imageElem, oldImg);
- }
/**
* Ensure that the animation frame exists and return it.
@@ -650,45 +626,72 @@
contentContainer = Document.get().createDivElement();
ensureAnimationFrame().appendChild(contentContainer);
- loadingMessageElem = Document.get().createDivElement();
- loadingMessageElem.setInnerHTML(tree.getLoadingHtml());
- showOrHide(loadingMessageElem, false);
- contentContainer.appendChild(loadingMessageElem);
-
// TODO(jlabanca): I18N no data string.
emptyMessageElem = Document.get().createDivElement();
- emptyMessageElem.setInnerHTML("<i>no data</i>");
+ emptyMessageElem.setInnerHTML("no data");
+ setStyleName(emptyMessageElem, tree.getStyle().emptyMessage(), true);
showOrHide(emptyMessageElem, false);
contentContainer.appendChild(emptyMessageElem);
- showMoreElem = Document.get().createPushButtonElement();
+ showMoreElem = Document.get().createAnchorElement();
+ showMoreElem.setHref("javascript:;");
showMoreElem.setInnerText("Show more");
+ setStyleName(showMoreElem, tree.getStyle().showMoreButton(), true);
showOrHide(showMoreElem, false);
contentContainer.appendChild(showMoreElem);
-
- showFewerElem = Document.get().createPushButtonElement();
- showFewerElem.setInnerText("Show fewer");
- showOrHide(showFewerElem, false);
- contentContainer.appendChild(showFewerElem);
}
return contentContainer;
}
-
- Element getShowFewerElement() {
- return showFewerElem;
- }
Element getShowMoreElement() {
return showMoreElem;
}
void showFewer() {
- int maxSize = Math.max(DEFAULT_LIST_SIZE, listView.impl.getPageSize()
- - DEFAULT_LIST_SIZE);
+ int defaultPageSize = listView.getDefaultPageSize();
+ int maxSize = Math.max(defaultPageSize, listView.impl.getPageSize()
+ - defaultPageSize);
listView.impl.setPageSize(maxSize);
}
void showMore() {
- listView.impl.setPageSize(listView.impl.getPageSize() +
DEFAULT_LIST_SIZE);
+ listView.impl.setPageSize(listView.impl.getPageSize()
+ + listView.getDefaultPageSize());
+ }
+
+ /**
+ * Check if this node is a root node.
+ *
+ * @return true if a root node
+ */
+ private boolean isRootNode() {
+ return parentNode == null;
+ }
+
+ /**
+ * Update the image based on the current state.
+ *
+ * @param isLoading true if still loading data
+ */
+ private void updateImage(boolean isLoading) {
+ // Early out if this is a root node.
+ if (isRootNode()) {
+ return;
+ }
+
+ // Replace the image element with a new one.
+ String html = tree.getClosedImageHtml();
+ if (open) {
+ html = isLoading ? tree.getLoadingImageHtml() :
tree.getOpenImageHtml();
+ }
+ if (nodeInfoLoaded && nodeInfo == null) {
+ html = LEAF_IMAGE;
+ }
+ Element tmp = Document.get().createDivElement();
+ tmp.setInnerHTML(html);
+ Element imageElem = tmp.getFirstChildElement();
+
+ Element oldImg = getImageElement();
+ oldImg.getParentElement().replaceChild(imageElem, oldImg);
}
}
=======================================
---
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseTree.java
Mon May 3 11:15:42 2010
+++
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseTree.java
Tue May 4 10:22:18 2010
@@ -18,26 +18,32 @@
import com.google.gwt.bikeshed.cells.client.Cell;
import com.google.gwt.bikeshed.cells.client.IconCellDecorator;
import com.google.gwt.bikeshed.cells.client.TextCell;
+import com.google.gwt.bikeshed.list.client.ListView;
+import com.google.gwt.bikeshed.list.shared.AsyncListViewAdapter;
import com.google.gwt.bikeshed.list.shared.ListViewAdapter;
import com.google.gwt.bikeshed.list.shared.ProvidesKey;
+import com.google.gwt.bikeshed.list.shared.Range;
import com.google.gwt.bikeshed.list.shared.SingleSelectionModel;
import
com.google.gwt.bikeshed.list.shared.SelectionModel.SelectionChangeEvent;
import
com.google.gwt.bikeshed.list.shared.SelectionModel.SelectionChangeHandler;
import com.google.gwt.bikeshed.tree.client.CellTree;
import com.google.gwt.bikeshed.tree.client.CellTreeViewModel;
+import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.sample.bikeshed.style.client.Styles;
import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
-import com.google.gwt.sample.expenses.gwt.request.EmployeeRecordChanged;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
import com.google.gwt.user.client.ui.Composite;
-
+import com.google.gwt.valuestore.shared.Property;
+
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
* The employee tree located on the left of the app.
*/
-public class ExpenseTree extends Composite implements
- Receiver<List<EmployeeRecord>>, EmployeeRecordChanged.Handler {
+public class ExpenseTree extends Composite {
/**
* Custom listener for this widget.
@@ -47,10 +53,10 @@
/**
* Called when the user selects a tree item.
*
- * @param category the selected category name
+ * @param department the selected department name
* @param employee the selected employee
*/
- void onSelection(String category, EmployeeRecord employee);
+ void onSelection(String department, EmployeeRecord employee);
}
/**
@@ -71,6 +77,45 @@
});
}
}
+
+ /**
+ * The {...@link ListViewAdapter} used for Employee lists.
+ */
+ private class EmployeeListViewAdapter extends
+ AsyncListViewAdapter<EmployeeRecord> implements
+ Receiver<List<EmployeeRecord>> {
+
+ private final String department;
+
+ public EmployeeListViewAdapter(String department) {
+ this.department = department;
+ }
+
+ @Override
+ public void addView(ListView<EmployeeRecord> view) {
+ super.addView(view);
+
+ // Request the count anytime a view is added.
+
requestFactory.employeeRequest().countEmployeesByDepartment(department).to(
+ new Receiver<Long>() {
+ public void onSuccess(Long response) {
+ updateDataSize(response.intValue(), true);
+ }
+ }).fire();
+ }
+
+ public void onSuccess(List<EmployeeRecord> response) {
+ updateViewData(0, response.size(), response);
+ }
+
+ @Override
+ protected void onRangeChanged(ListView<EmployeeRecord> view) {
+ Range range = view.getRange();
+ requestFactory.employeeRequest().findEmployeeEntriesByDepartment(
+ department, range.getStart(), range.getLength()).forProperties(
+ getEmployeeMenuProperties()).to(this).fire();
+ }
+ }
/**
* The {...@link CellTreeViewModel} used to browse expense reports.
@@ -78,9 +123,9 @@
private class ExpensesTreeViewModel implements CellTreeViewModel {
/**
- * The category cell singleton.
+ * The department cell singleton.
*/
- private final Cell<String> categoryCell = new
IconCellDecorator<String>(
+ private final Cell<String> departmentCell = new
IconCellDecorator<String>(
Styles.resources().groupIcon(), TextCell.getInstance());
/**
@@ -91,11 +136,16 @@
public <T> NodeInfo<?> getNodeInfo(T value) {
if (value == null) {
// Top level.
- return new DefaultNodeInfo<String>(categories, categoryCell,
+ return new DefaultNodeInfo<String>(departments, departmentCell,
selectionModel, null);
+ } else if (isAllDepartment(value)) {
+ // Employees are not displayed under the 'All' Department.
+ return null;
} else if (value instanceof String) {
// Second level.
- return new DefaultNodeInfo<EmployeeRecord>(employees, employeeCell,
+ EmployeeListViewAdapter adapter = new EmployeeListViewAdapter(
+ (String) value);
+ return new DefaultNodeInfo<EmployeeRecord>(adapter, employeeCell,
selectionModel, null);
}
@@ -103,31 +153,36 @@
}
public boolean isLeaf(Object value) {
- return !isCategory(value);
+ return !isDepartment(value) || isAllDepartment(value);
}
- private boolean isCategory(Object value) {
- return categories.getList().contains(value.toString());
+ /**
+ * @return true if the object is the All department
+ */
+ private boolean isAllDepartment(Object value) {
+ return departments.getList().get(0).equals(value);
+ }
+
+ /**
+ * @return true if the object is a department
+ */
+ private boolean isDepartment(Object value) {
+ return departments.getList().contains(value.toString());
}
}
/**
- * The adapter that provides categories.
+ * The adapter that provides departments.
*/
- private ListViewAdapter<String> categories = new
ListViewAdapter<String>();
+ private ListViewAdapter<String> departments = new
ListViewAdapter<String>();
/**
- * The adapter that provides employees.
+ * The last selected department.
*/
- private ListViewAdapter<EmployeeRecord> employees = new
ListViewAdapter<EmployeeRecord>();
+ private String lastDepartment;
/**
- * The last selected category.
- */
- private String lastCategory;
-
- /**
- * The last selected category.
+ * The last selected employee.
*/
private EmployeeRecord lastEmployee;
@@ -136,6 +191,11 @@
*/
private Listener listener;
+ /**
+ * The factory used to send requests.
+ */
+ private ExpensesRequestFactory requestFactory;
+
/**
* The shared {...@link SingleSelectionModel}.
*/
@@ -149,26 +209,26 @@
public ExpenseTree() {
createTree();
initWidget(tree);
-
- // Initialize the categories.
- List<String> categoriesList = categories.getList();
- categoriesList.add("All");
- categoriesList.add("Sales");
- categoriesList.add("Marketing");
- categoriesList.add("Engineering");
- }
-
- public void onEmployeeChanged(EmployeeRecordChanged event) {
- employees.refresh();
- }
-
- public void onSuccess(List<EmployeeRecord> response) {
- employees.setList(response);
+ getElement().getStyle().setOverflow(Overflow.AUTO);
+
+ // Initialize the departments.
+ List<String> departmentList = departments.getList();
+ departmentList.add("All");
+ departmentList.add("Engineering");
+ // The Finance department is empty.
+ departmentList.add("Finance");
+ departmentList.add("Marketing");
+ departmentList.add("Operations");
+ departmentList.add("Sales");
}
public void setListener(Listener listener) {
this.listener = listener;
}
+
+ public void setRequestFactory(ExpensesRequestFactory factory) {
+ this.requestFactory = factory;
+ }
/**
* Create the {...@link CellTree}.
@@ -181,16 +241,16 @@
Object selected = selectionModel.getSelectedObject();
if (selected == null) {
lastEmployee = null;
- lastCategory = null;
+ lastDepartment = null;
} else if (selected instanceof EmployeeRecord) {
lastEmployee = (EmployeeRecord) selected;
} else if (selected instanceof String) {
lastEmployee = null;
- lastCategory = (String) selected;
+ lastDepartment = (String) selected;
}
if (listener != null) {
- listener.onSelection(lastCategory, lastEmployee);
+ listener.onSelection(lastDepartment, lastEmployee);
}
}
});
@@ -207,4 +267,11 @@
tree = new CellTree(new ExpensesTreeViewModel(), null);
tree.setAnimationEnabled(true);
}
-}
+
+ private Collection<Property<?>> getEmployeeMenuProperties() {
+ List<Property<?>> columns = new ArrayList<Property<?>>();
+ columns.add(EmployeeRecord.displayName);
+ columns.add(EmployeeRecord.userName);
+ return columns;
+ }
+}
=======================================
---
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/Expenses.java
Mon May 3 11:15:42 2010
+++
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/Expenses.java
Tue May 4 10:22:18 2010
@@ -48,7 +48,6 @@
};
private ExpensesRequestFactory requestFactory;
- private String searchCategory;
private ExpensesShell shell;
public void onModuleLoad() {
@@ -67,17 +66,12 @@
// Listen for requests from ExpenseTree.
expenseTree.setListener(new ExpenseTree.Listener() {
- public void onSelection(String category, EmployeeRecord employee) {
- if (category != null && !category.equals(searchCategory)) {
- // TODO(jlabanca): Limit employees using category.
-
requestFactory.employeeRequest().findAllEmployees().forProperties(
- getEmployeeMenuProperties()).to(expenseTree).fire();
- }
- searchCategory = category;
+ public void onSelection(String department, EmployeeRecord employee) {
expenseList.setEmployee(employee);
shell.showExpenseDetails(false);
}
});
+ expenseTree.setRequestFactory(requestFactory);
// Listen for requests from the ExpenseList.
expenseList.setListener(new ExpenseList.Listener() {
@@ -96,13 +90,6 @@
eventBus.addHandler(ExpenseRecordChanged.TYPE, expenseDetails);
}
-
- private Collection<Property<?>> getEmployeeMenuProperties() {
- List<Property<?>> columns = new ArrayList<Property<?>>();
- columns.add(EmployeeRecord.displayName);
- columns.add(EmployeeRecord.userName);
- return columns;
- }
private Collection<Property<?>> getExpenseColumns() {
List<Property<?>> columns = new ArrayList<Property<?>>();
=======================================
---
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java
Sat May 1 07:18:49 2010
+++
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java
Tue May 4 10:22:18 2010
@@ -38,6 +38,24 @@
public String getDomainMethodName() {
return "countEmployees";
}
+
+ public Class<?> getReturnType() {
+ return Long.class;
+ }
+
+ public boolean isReturnTypeList() {
+ return false;
+ }
+ },
+
+ COUNT_EMPLOYEES_BY_DEPARTMENT {
+ public String getDomainMethodName() {
+ return "countEmployeesByDepartment";
+ }
+
+ public Class<?>[] getParameterTypes() {
+ return new Class[]{java.lang.String.class};
+ }
public Class<?> getReturnType() {
return Long.class;
@@ -74,7 +92,17 @@
}
public Class<?>[] getParameterTypes() {
- return new Class[] {int.class, int.class};
+ return new Class[]{int.class, int.class};
+ }
+ },
+
+ FIND_EMPLOYEE_ENTRIES_BY_DEPARTMENT {
+ public String getDomainMethodName() {
+ return "findEmployeeEntriesByDepartment";
+ }
+
+ public Class<?>[] getParameterTypes() {
+ return new Class[]{java.lang.String.class, int.class, int.class};
}
};
@@ -101,6 +129,13 @@
@ServerOperation("COUNT_EMPLOYEES")
RequestFactory.RequestObject<Long> countEmployees();
+ /**
+ * @return a request object
+ */
+ @ServerOperation("COUNT_EMPLOYEES_BY_DEPARTMENT")
+ RequestFactory.RequestObject<Long> countEmployeesByDepartment(
+ String department);
+
/**
* @return a request object
*/
@@ -119,4 +154,11 @@
@ServerOperation("FIND_EMPLOYEE_ENTRIES")
RecordListRequest<EmployeeRecord> findEmployeeEntries(int firstResult,
int maxResults);
-}
+
+ /**
+ * @return a request object
+ */
+ @ServerOperation("FIND_EMPLOYEE_ENTRIES_BY_DEPARTMENT")
+ RecordListRequest<EmployeeRecord> findEmployeeEntriesByDepartment(
+ String department, int firstResult, int maxResults);
+}
=======================================
---
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java
Mon May 3 11:15:42 2010
+++
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java
Tue May 4 10:22:18 2010
@@ -32,121 +32,108 @@
// Must be in sync with DESCRIPTIONS
private static final String[] CATEGORIES = {
- "Dining", "Dining", "Dining",
- "Lodging", "Lodging",
- "Local Transportation", "Local Transportation", "Local Transportation",
- "Air Travel", "Air Travel",
- "Office Supplies", "Office Supplies", "Office Supplies", "Office
Supplies",
- };
+ "Dining", "Dining", "Dining", "Lodging", "Lodging",
+ "Local Transportation", "Local Transportation", "Local
Transportation",
+ "Air Travel", "Air Travel", "Office Supplies", "Office Supplies",
+ "Office Supplies", "Office Supplies",};
+
+ private static final String[] DEPARTMENTS = {
+ "Sales", "Marketing", "Engineering", "Operations"};
// Must be in sync with CATEGORIES
private static final String[] DESCRIPTIONS = {
- "Breakfast", "Lunch", "Dinner",
- "Hotel", "Bed & Breakfast",
- "Train fare", "Taxi fare", "Bus ticket",
- "Flight from ATL to SFO", "Flight from SFO to ATL",
- "Paperclips", "Stapler", "Scissors", "Paste",
- };
-
+ "Breakfast", "Lunch", "Dinner", "Hotel", "Bed & Breakfast", "Train
fare",
+ "Taxi fare", "Bus ticket", "Flight from ATL to SFO",
+ "Flight from SFO to
ATL", "Paperclips", "Stapler", "Scissors", "Paste",};
+
+ private static final String[] FIRST_NAMES = {
+ "Amy", "Bob", "Catherine", "Dave", "Earl", "Flin", "George", "Harriot",
+ "Ingrid", "John", "Katy", "Leo", "Mike", "Nancy", "Owen", "Paul",
+ "Reece", "Sally", "Terry", "Val", "Wes", "Xavier", "Zack"};
+
+ private static final String[] LAST_NAMES = {
+ "Awesome", "Bravo", "Cool", "Fantastic", "Great", "Happy",
+ "Ignoranomous", "Krazy", "Luminous", "Magnanimous", "Outstanding",
+ "Perfect", "Radical", "Stellar", "Terrific", "Wonderful"};
+
private static final String[] NOTES = {
- "Need approval by Monday", "Show me the money",
- "Please bill to the Widgets project",
- "High priority",
- "Review A.S.A.P."
- };
+ // Some entries do not have notes.
+ "", "Need approval by Monday", "Show me the money",
+ "Please bill to the Widgets project", "High priority", "Review
A.S.A.P."};
+
+ private static final String[] PURPOSES = {
+ "Spending lots of money", "Team building diamond cutting offsite",
+ "Visit to Istanbul", "ISDN modem for telecommuting", "Sushi offsite",
+ "Baseball card research", "Potato chip cooking offsite",
+ "Money laundering", "Donut day"};
Random rand = new Random();
-
+
@Override
protected void initDb() {
long size = Employee.countEmployees();
if (size > 1) {
return;
}
- // initialize
- Employee abc = new Employee();
- abc.setUserName("abc");
- abc.setDisplayName("Able B. Charlie");
- abc.persist();
-
- Employee def = new Employee();
- def.setUserName("def");
- def.setDisplayName("Delta E. Foxtrot");
- def.setSupervisorKey(abc.getId());
- def.persist();
-
- Employee ghi = new Employee();
- ghi.setUserName("ghi");
- ghi.setDisplayName("George H. Indigo");
- ghi.setSupervisorKey(abc.getId());
- ghi.persist();
-
- for (String purpose : new String[] {
- "Spending lots of money", "Team building diamond cutting offsite",
- "Visit to Istanbul"}) {
- Report report = new Report();
- report.setReporterKey(abc.getId());
- report.setCreated(getDate());
- report.setPurpose(purpose);
- report.setNotes(getNote());
- report.persist();
-
- addExpenses(report.getId());
- }
-
- for (String purpose : new String[] {"Money laundering", "Donut day"}) {
- Report report = new Report();
- report.setCreated(getDate());
- report.setReporterKey(def.getId());
- report.setPurpose(purpose);
- report.setNotes(getNote());
- report.persist();
-
- addExpenses(report.getId());
- }
-
- for (String purpose : new String[] {
- "ISDN modem for telecommuting", "Sushi offsite",
- "Baseball card research", "Potato chip cooking offsite"}) {
- Report report = new Report();
- report.setCreated(getDate());
- report.setReporterKey(ghi.getId());
- report.setPurpose(purpose);
- report.setNotes(getNote());
- report.persist();
-
- addExpenses(report.getId());
- }
-
- for (int i = 0; i < 1000; i++) {
- Report report = new Report();
- report.setCreated(getDate());
- report.setReporterKey(ghi.getId());
- report.setPurpose("Report " + i);
- report.setNotes(getNote());
- report.persist();
-
- addExpenses(report.getId());
- }
- }
-
+
+ // Initialize the database.
+ for (int i = 0; i < 100; i++) {
+ addEmployee();
+ }
+ }
+
+ /**
+ * Add a randomly generated employee.
+ */
+ private void addEmployee() {
+ Employee abc = new Employee();
+ String firstName = nextValue(FIRST_NAMES);
+ String lastName = nextValue(LAST_NAMES);
+ String username = (firstName.charAt(0) + lastName).toLowerCase();
+ abc.setUserName(username);
+ abc.setDisplayName(firstName + " " + lastName);
+ abc.setDepartment(nextValue(DEPARTMENTS));
+ abc.persist();
+
+ addReports(abc.getId());
+ }
+
private void addExpenses(Long reportId) {
int num = rand.nextInt(5) + 1;
for (int i = 0; i < num; i++) {
- String[] descCat = getDescriptionAndCategory();
-
+ int index = rand.nextInt(DESCRIPTIONS.length);
Expense detail = new Expense();
detail.setReportId(reportId);
- detail.setDescription(descCat[0]);
+ detail.setDescription(DESCRIPTIONS[index]);
detail.setDate(getDate());
detail.setAmount(rand.nextInt(25000) / 100.0);
- detail.setCategory(descCat[1]);
+ detail.setCategory(CATEGORIES[index]);
detail.setApproval("");
detail.setReasonDenied("");
detail.persist();
}
}
-
+
+ /**
+ * Add a randomly generated report.
+ *
+ * @param employeeId the id of the employee who created the report
+ */
+ private void addReports(Long employeeId) {
+ // Add 1-20 expense reports.
+ int reportCount = 1 + rand.nextInt(20);
+ for (int i = 0; i < reportCount; i++) {
+ Report report = new Report();
+ report.setCreated(getDate());
+ report.setReporterKey(employeeId);
+ report.setPurpose(nextValue(PURPOSES));
+ report.setNotes(nextValue(NOTES));
+ report.persist();
+
+ addExpenses(report.getId());
+ }
+ }
+
private Date getDate() {
long now = new Date().getTime();
// Go back up to 90 days from the current date
@@ -154,15 +141,13 @@
return new Date(now - dateOffset);
}
- private String[] getDescriptionAndCategory() {
- String[] dc = new String[2];
- int index = rand.nextInt(DESCRIPTIONS.length);
- dc[0] = DESCRIPTIONS[index];
- dc[1] = CATEGORIES[index];
- return dc;
- }
-
- private String getNote() {
- return NOTES[rand.nextInt(NOTES.length)];
+ /**
+ * Get the next random value from an array.
+ *
+ * @param array the array
+ * @return a random value from the array
+ */
+ private String nextValue(String[] array) {
+ return array[rand.nextInt(array.length)];
}
}
=======================================
---
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Employee.java
Mon May 3 13:28:30 2010
+++
/branches/2.1/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Employee.java
Tue May 4 10:22:18 2010
@@ -23,6 +23,7 @@
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
+import javax.persistence.Query;
import javax.persistence.Version;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@@ -41,6 +42,17 @@
em.close();
}
}
+
+ public static long countEmployeesByDepartment(String department) {
+ EntityManager em = entityManager();
+ try {
+ Query query = em.createQuery("select count(o) from Employee o where
o.department=:department");
+ query.setParameter("department", department);
+ return ((Number) query.getSingleResult()).longValue();
+ } finally {
+ em.close();
+ }
+ }
public static final EntityManager entityManager() {
return EMF.get().createEntityManager();
@@ -85,10 +97,30 @@
em.close();
}
}
+
+ @SuppressWarnings("unchecked")
+ public static List<Employee> findEmployeeEntriesByDepartment(
+ String department, int firstResult, int maxResults) {
+ EntityManager em = entityManager();
+ try {
+ Query query = em.createQuery("select o from Employee o WHERE
o.department =:department");
+ query.setFirstResult(firstResult);
+ query.setMaxResults(maxResults);
+ query.setParameter("department", department);
+ List resultList = query.getResultList();
+ // force it to materialize
+ resultList.size();
+ return resultList;
+ } finally {
+ em.close();
+ }
+ }
@Size(min = 3, max = 30)
private String userName;
+ private String department;
+
@NotNull
private String displayName;
@@ -106,6 +138,10 @@
@Column(name = "version")
private Integer version;
+ public String getDepartment() {
+ return department;
+ }
+
public String getDisplayName() {
return this.displayName;
}
@@ -148,6 +184,10 @@
em.close();
}
}
+
+ public void setDepartment(String department) {
+ this.department = department;
+ }
public void setDisplayName(String displayName) {
this.displayName = displayName;
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors