1
2
3
4
5
6
7
8
9
10 package com.sri.emo.controller;
11
12 import com.jcorporate.expresso.core.controller.*;
13 import com.jcorporate.expresso.core.db.DBException;
14 import com.jcorporate.expresso.core.registry.RequestRegistry;
15 import com.jcorporate.expresso.services.controller.ui.DefaultAutoElement;
16 import com.sri.common.controller.AbstractDBController;
17 import com.sri.common.taglib.InputTag;
18 import com.sri.emo.dbobj.*;
19 import org.apache.log4j.Logger;
20
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.Iterator;
24 import java.util.List;
25
26
27 /***
28 * handle Picklist manipulation
29 *
30 * @author larry hamel
31 */
32 public class PicklistAction extends AbstractDBController {
33
34
35 /***
36 *
37 */
38 private static final long serialVersionUID = 1L;
39
40 /***
41 * edit picklist state
42 */
43 public static final String PROMPT_LIST = "promptEditPicklist";
44
45
46 public static final String PROMPT_EDIT_ITEM = "promptEditItem";
47
48 /***
49 * Constant value for state 'Save Picklist Item'
50 */
51 public static final String DO_EDIT_ITEM = "doEditItem";
52
53
54 public static final String DO_INC_ITEM_ORDER = "doIncItemOrder";
55 public static final String DO_DEC_ITEM_ORDER = "doDecItemOrder";
56 public static final String PROMPT_ADD_ITEM = "promptAddItem";
57 public static final String DO_ADD_ITEM = "doAddItem";
58 public static final String SORT_BY_ALPHA = "sortByAlpha";
59 public static final String PROMPT_DELETE_ITEM = "promptDeleteItem";
60 public static final String DO_DELETE_ITEM = "doDeleteItem";
61
62 /***
63 * Constant value for state 'List All Picklists'
64 */
65 public static final String LIST_PICKLISTS = "listPickLists";
66
67
68 public static final String NEW_ITEM_PREFIX = "newprefix";
69 public static final String EXISTING_ITEM_PREFIX = "existprefix";
70 public static final String ASSOCIATE_PREFIX = "associateprefix";
71
72 public PicklistAction() {
73 State state = new State(PROMPT_LIST, "Prompt to edit a picklist");
74 addState(state);
75
76
77
78 addState(new State(PROMPT_EDIT_ITEM, "Prompt edit single picklist item"));
79 addState(new State(DO_EDIT_ITEM,
80 "submit editting of single picklist item"));
81
82 addState(new State(DO_INC_ITEM_ORDER,
83 "increment order number of pick item"));
84 addState(new State(DO_DEC_ITEM_ORDER,
85 "decrement order number of pick item"));
86
87 addState(new State(PROMPT_ADD_ITEM, "prompt add new pick item"));
88 addState(new State(DO_ADD_ITEM, "execute add new pick item"));
89
90 addState(new State(PROMPT_DELETE_ITEM, "prompt delete pick item"));
91 addState(new State(DO_DELETE_ITEM, "execute delete pick item"));
92
93 addState(new State(SORT_BY_ALPHA, "sort items by alpha"));
94
95
96 setInitialState(PROMPT_LIST);
97 }
98
99 /***
100 * Returns the title of this controller
101 *
102 * @return java.lang.String
103 */
104 public String getTitle() {
105 return ("PicklistAction Controller");
106 }
107
108 /***
109 * Prompt for edits.
110 *
111 * @param request The ExpressoRequest object.
112 * @param response The ExpressoResponse object.
113 * @throws ControllerException upon error.
114 */
115 protected void runPromptEditPicklistState(ExpressoRequest request,
116 ExpressoResponse response) throws ControllerException {
117 try {
118
119 PickList item = new PickList();
120 String[] required = {PickList.NODE_TYPE, PickList.ATTRIBUTE_TYPE};
121
122 if (!isValidAndPopulated(item, required, null, request, response)) {
123 Transition trans = new Transition(AddNodeAction.PROMPT_EDIT_NODE,
124 "", AddNodeAction.class, AddNodeAction.PROMPT_EDIT_NODE);
125 trans.addParam(Node.NODE_TYPE,
126 request.getParameter(PickList.NODE_TYPE));
127 trans.addParam(Node.NODE_ID, request.getParameter(Node.NODE_ID));
128 trans.executeTransition(request, response);
129
130 return;
131 }
132
133
134 Input hiddenInput = new Input(PickList.NODE_TYPE);
135 hiddenInput.setType(InputTag.TYPE_HIDDEN);
136 hiddenInput.setDefaultValue(item.getNodeType());
137 response.add(hiddenInput);
138 hiddenInput = new Input(PickList.ATTRIBUTE_TYPE);
139 hiddenInput.setType(InputTag.TYPE_HIDDEN);
140 hiddenInput.setDefaultValue(item.getPickAttribType());
141 response.add(hiddenInput);
142
143
144 Part part = PartsFactory.getAttribPart(item.getNodeType(), item.getPickAttribType());
145
146 if (part == null) {
147
148 throw new ControllerException(
149 "Cannot find part corresponding to Node/Attribute: " + item.getNodeType() + "/" + item.getPickAttribType());
150 }
151 Output output = new Output(PickList.NODE_TYPE,
152 part.getDisplayTitleOfParentNodeType(RequestRegistry.getUser().getUid()));
153 response.add(output);
154 output = new Output(PickList.ATTRIBUTE_TYPE, part.getPartLabel());
155 response.add(output);
156
157 Block outerBlock = new Block(ROW_BLOCK);
158 response.add(outerBlock);
159
160
161 List list = item.searchAndRetrieveList(PickList.DISPLAY_IN_PICKLIST);
162 Collections.sort(list);
163
164 int i = 0;
165
166 for (Iterator iter = list.iterator(); iter.hasNext();) {
167 PickList anItem = (PickList) iter.next();
168
169 Block rowBlock = new Block(ROW);
170 outerBlock.add(rowBlock);
171
172 rowBlock.add(new Output(PickList.COMMENT, anItem.getComment()));
173 rowBlock.add(new Output(PickList.LIST_ID, anItem.getID()));
174 rowBlock.add(new Output(PickList.ORDER_NUM, anItem.getOrderNum()));
175 rowBlock.add(new Output(Node.RELATED,
176 "" +
177 getAttributesUsingPickItem(anItem).size()));
178
179 Transition trans = new Transition(anItem.getDisplayString(),
180 getClass(), PROMPT_EDIT_ITEM);
181 trans.addParam(PickList.LIST_ID, anItem.getID());
182 rowBlock.add(trans);
183
184 trans = new Transition(PROMPT_DELETE_ITEM, this);
185 trans.addParam(PickList.LIST_ID, anItem.getID());
186 rowBlock.add(trans);
187
188
189 if (i < (list.size() - 1)) {
190 trans = new Transition(DO_INC_ITEM_ORDER + "_" +
191 anItem.getID(), "", getClass(), DO_INC_ITEM_ORDER);
192 trans.addParam(PickList.LIST_ID, anItem.getID());
193 rowBlock.add(trans);
194 }
195
196
197 if (i > 0) {
198 trans = new Transition(DO_DEC_ITEM_ORDER + "_" +
199 anItem.getID(), "", getClass(), DO_DEC_ITEM_ORDER);
200 trans.addParam(PickList.LIST_ID, anItem.getID());
201 rowBlock.add(trans);
202 }
203
204 i++;
205 }
206
207 Transition trans = new Transition(PROMPT_ADD_ITEM, this);
208 trans.addParam(PickList.ATTRIBUTE_TYPE, item.getPickAttribType());
209 trans.addParam(PickList.NODE_TYPE, item.getNodeType());
210 response.add(trans);
211
212 trans = new Transition(SORT_BY_ALPHA, this);
213 trans.addParam(PickList.ATTRIBUTE_TYPE, item.getPickAttribType());
214 trans.addParam(PickList.NODE_TYPE, item.getNodeType());
215 response.add(trans);
216 } catch (Exception e) {
217 throw new ControllerException(e);
218 }
219 }
220
221 /***
222 * Prompt for editing single pick item.
223 *
224 * @param request The ExpressoRequest object.
225 * @param response The ExpressoResponse object.
226 * @throws ControllerException upon error.
227 */
228 protected void runPromptEditItemState(ExpressoRequest request,
229 ExpressoResponse response) throws ControllerException {
230 try {
231 PickList item = getPicklistItem(request);
232 Block b = DefaultAutoElement.getAutoControllerElement()
233 .createDBObjectBlock(request, response,
234 item);
235 response.add(b);
236
237 Transition trans = new Transition(item.getDisplayString(),
238 getClass(), DO_EDIT_ITEM);
239 trans.addParam(PickList.LIST_ID, item.getID());
240 response.add(trans);
241
242
243 List list = getAttributesUsingPickItem(item);
244 addLinksForNodes(response, list);
245 } catch (Exception e) {
246 throw new ControllerException(e);
247 }
248 }
249
250 private void addLinksForNodes(ExpressoResponse response, List list)
251 throws ControllerException, DBException {
252 Transition trans;
253 Block block = new Block(ROW_BLOCK);
254 response.add(block);
255
256 for (Iterator iterator = list.iterator(); iterator.hasNext();) {
257 Attribute anAttrib = (Attribute) iterator.next();
258 Node node = anAttrib.getParentNode();
259 trans = new Transition(node.getNodeTitle(), AddNodeAction.class,
260 AddNodeAction.VIEW_NODE);
261 trans.addParam(Node.NODE_ID, anAttrib.getParentNodeId());
262 block.add(trans);
263 }
264 }
265
266 private List getAttributesUsingPickItem(
267 PickList item) throws DBException {
268 Attribute attrib = new Attribute();
269 attrib.setRequestingUser(RequestRegistry.getUser());
270 attrib.setAttributeType(item.getPickAttribType());
271 attrib.setParentNodeType(item.getNodeType());
272 attrib.setAttributeValue(item.getID());
273
274 return (List) attrib.searchAndRetrieveList();
275 }
276
277 private PickList getPicklistItem(ExpressoRequest request)
278 throws DBException {
279 String id = request.getParameter(PickList.LIST_ID);
280
281 if (id == null) {
282 throw new DBException("Cannot find picklist ID parameter");
283 }
284
285 PickList pick = new PickList();
286 pick.setID(id);
287 pick.retrieve();
288
289 return pick;
290 }
291
292 /***
293 * Do for editing single pick item.
294 *
295 * @param request The ExpressoRequest object.
296 * @param response The ExpressoResponse object.
297 * @throws ControllerException upon error.
298 */
299 protected void runDoEditItemState(ExpressoRequest request,
300 ExpressoResponse response) throws ControllerException {
301 try {
302 PickList item = getPicklistItem(request);
303 ErrorCollection ec = new ErrorCollection();
304 item = (PickList) DefaultAutoElement.getAutoControllerElement()
305 .parseDBObject(request, item, ec);
306
307 if (!ec.isEmpty()) {
308 response.saveErrors(ec);
309 response.setFormCache();
310
311 Transition trans = new Transition(PROMPT_EDIT_ITEM, this);
312 trans.addParam(PickList.LIST_ID, item.getID());
313 trans.executeTransition(request, response);
314
315 return;
316 }
317
318 item.update(true);
319
320 Transition trans = getListTrans(item);
321 trans.redirectTransition(request, response);
322 } catch (Exception e) {
323 throw new ControllerException(e);
324 }
325 }
326
327 private Transition getListTrans(PickList item) throws DBException {
328 Transition trans = new Transition(PROMPT_LIST, this);
329 trans.addParam(PickList.ATTRIBUTE_TYPE, item.getPickAttribType());
330 trans.addParam(PickList.NODE_TYPE, item.getNodeType());
331
332 return trans;
333 }
334
335 /***
336 * Prompt for deleting single pick item.
337 *
338 * @param request The ExpressoRequest object.
339 * @param response The ExpressoResponse object.
340 * @throws ControllerException upon error.
341 */
342 protected void runPromptDeleteItemState(ExpressoRequest request,
343 ExpressoResponse response) throws ControllerException {
344 try {
345 PickList item = getPicklistItem(request);
346 response.add(new Output(PickList.DISPLAY_IN_PICKLIST,
347 item.getDisplayString()));
348
349 List list = getSortedList(item);
350 List usagelist = getAttributesUsingPickItem(item);
351
352
353 if ((usagelist.size() > 0) && (list.size() <= 1)) {
354 response.addError("Cannot delete last item in list because there are usages.");
355 response.setFormCache();
356
357 Transition trans = new Transition(PROMPT_LIST, this);
358 trans.addParam(PickList.ATTRIBUTE_TYPE, item.getPickAttribType());
359 trans.addParam(PickList.NODE_TYPE, item.getNodeType());
360 trans.executeTransition(request, response);
361
362 return;
363 } else {
364
365 if (usagelist.size() > 0) {
366 PickList changeto = (PickList) list.get(0);
367
368 if (item.getID().equals(changeto.getID())) {
369 changeto = (PickList) list.get(1);
370 }
371
372 addWarning(request,
373 usagelist.size() +
374 " usages of this choice will be changed to choice: '" +
375 changeto.getDisplayString() +
376 "' after deletion. (See edit screen for item to see details on usages).");
377 }
378 }
379
380 Transition trans = new Transition("Delete", getClass(),
381 DO_DELETE_ITEM);
382 trans.addParam(PickList.LIST_ID, item.getID());
383 response.add(trans);
384 } catch (Exception e) {
385 throw new ControllerException(e);
386 }
387 }
388
389 /***
390 * Delete single pick item.
391 *
392 * @param request The ExpressoRequest object.
393 * @param response The ExpressoResponse object.
394 * @throws ControllerException upon error.
395 */
396 protected void runDoDeleteItemState(ExpressoRequest request,
397 ExpressoResponse response) throws ControllerException {
398 try {
399 PickList item = getPicklistItem(request);
400
401 List list = getSortedList(item);
402 List usagelist = getAttributesUsingPickItem(item);
403
404
405 if ((usagelist.size() > 0) && (list.size() == 1)) {
406 response.addError("Cannot delete last item in list because there are usages.");
407 response.setFormCache();
408
409 Transition trans = new Transition(PROMPT_LIST, this);
410 trans.addParam(PickList.ATTRIBUTE_TYPE, item.getPickAttribType());
411 trans.addParam(PickList.NODE_TYPE, item.getNodeType());
412 trans.executeTransition(request, response);
413
414 return;
415 } else {
416
417 PickList changeto = (PickList) list.get(0);
418
419 if (item.getID().equals(changeto.getID())) {
420 changeto = (PickList) list.get(1);
421 }
422
423 for (Iterator iterator = usagelist.iterator();
424 iterator.hasNext();) {
425 Attribute attribute = (Attribute) iterator.next();
426 attribute.setAttributeValue(changeto.getID());
427 attribute.update();
428 }
429 }
430
431 item.delete();
432
433
434
435 int index = list.indexOf(item);
436
437
438 for (int i = index + 1; i < list.size(); i++) {
439 PickList anItem = (PickList) list.get(i);
440 anItem.setOrderNum(anItem.getOrderNumInt() - 1);
441 anItem.update();
442 }
443
444 Transition trans = getListTrans(item);
445 trans.redirectTransition(request, response);
446 } catch (Exception e) {
447 throw new ControllerException(e);
448 }
449 }
450
451 /***
452 * Increment pick item order number.
453 *
454 * @param request The ExpressoRequest object.
455 * @param response The ExpressoResponse object.
456 * @throws ControllerException upon error.
457 */
458 protected void runDoIncItemOrderState(ExpressoRequest request,
459 ExpressoResponse response) throws ControllerException {
460 try {
461 renumItems(request, response, true);
462 } catch (Exception e) {
463 throw new ControllerException(e);
464 }
465 }
466
467 /***
468 * Decrement pick item order number.
469 *
470 * @param request The ExpressoRequest object.
471 * @param response The ExpressoResponse object.
472 * @throws ControllerException upon error.
473 */
474 protected void runDoDecItemOrderState(ExpressoRequest request,
475 ExpressoResponse response) throws ControllerException {
476 try {
477 renumItems(request, response, false);
478 } catch (Exception e) {
479 throw new ControllerException(e);
480 }
481 }
482
483 /***
484 * Prompt to add pick item.
485 *
486 * @param request The ExpressoRequest object.
487 * @param response The ExpressoResponse object.
488 * @throws ControllerException upon error.
489 */
490 protected void runPromptAddItemState(ExpressoRequest request,
491 ExpressoResponse response) throws ControllerException {
492 try {
493 PickList item = new PickList();
494 String[] must = {PickList.NODE_TYPE, PickList.ATTRIBUTE_TYPE};
495 isValidAndPopulated(item, must, PROMPT_LIST, request, response);
496
497
498 List list = getSortedList(item);
499 item.setOrderNum(list.size());
500
501
502 Block b = DefaultAutoElement.getAutoControllerElement()
503 .createDBObjectBlock(request, response,
504 item);
505 response.add(b);
506
507 Transition trans = new Transition("Add", getClass(), DO_ADD_ITEM);
508 trans.addParam(PickList.NODE_TYPE, item.getNodeType());
509 trans.addParam(PickList.ATTRIBUTE_TYPE, item.getPickAttribType());
510 response.add(trans);
511 } catch (Exception e) {
512 throw new ControllerException(e);
513 }
514 }
515
516 /***
517 * Do to add pick item.
518 *
519 * @param request The ExpressoRequest object.
520 * @param response The ExpressoResponse object.
521 * @throws ControllerException upon error.
522 */
523 protected void runDoAddItemState(ExpressoRequest request,
524 ExpressoResponse response) throws ControllerException {
525 try {
526 PickList item = new PickList();
527 ErrorCollection ec = new ErrorCollection();
528 item = (PickList) DefaultAutoElement.getAutoControllerElement()
529 .parseDBObject(request, item, ec);
530
531 if (!ec.isEmpty()) {
532 response.saveErrors(ec);
533 response.setFormCache();
534
535 Transition trans = new Transition(PROMPT_ADD_ITEM, this);
536 trans.addParam(PickList.NODE_TYPE, item.getNodeType());
537 trans.addParam(PickList.ATTRIBUTE_TYPE, item.getPickAttribType());
538 trans.executeTransition(request, response);
539
540 return;
541 }
542
543 item.add();
544
545 Transition trans = getListTrans(item);
546 trans.redirectTransition(request, response);
547 } catch (Exception e) {
548 throw new ControllerException(e);
549 }
550 }
551
552 /***
553 * Sort by alpha of display name of items.
554 *
555 * @param request The ExpressoRequest object.
556 * @param response The ExpressoResponse object.
557 * @throws ControllerException upon error.
558 */
559 protected void runSortByAlphaState(ExpressoRequest request,
560 ExpressoResponse response) throws ControllerException {
561 try {
562 PickList item = new PickList();
563 String[] must = {PickList.NODE_TYPE, PickList.ATTRIBUTE_TYPE};
564 isValidAndPopulated(item, must, PROMPT_LIST, request, response);
565
566
567 List list = getSortedList(item);
568 Collections.sort(list, new ItemNameComparator());
569
570 int i = 0;
571
572 for (Iterator iterator = list.iterator(); iterator.hasNext();) {
573 PickList anItem = (PickList) iterator.next();
574 anItem.setOrderNum(i);
575 anItem.update();
576 i++;
577 }
578
579 Transition trans = getListTrans(item);
580 trans.redirectTransition(request, response);
581 } catch (Exception e) {
582 throw new ControllerException(e);
583 }
584 }
585
586 private void renumItems(ExpressoRequest request,
587 ExpressoResponse response, boolean isInc)
588 throws DBException, ControllerException {
589 PickList pick = getPicklistItem(request);
590
591 renumItems(pick, isInc);
592
593 Transition trans = getListTrans(pick);
594 trans.redirectTransition(request, response);
595 }
596
597 /***
598 * Renumber item specified, and all neighbors as necessary.
599 *
600 * @param item The Item we're changing the order for.
601 * @param isInc true if we're increasing the order number.
602 * @throws DBException upon error.
603 */
604 private void renumItems(PickList item, boolean isInc) throws DBException {
605 String order = item.getOrderNum();
606 int oldnum = 0;
607
608 if (order.length() > 0) {
609 oldnum = Integer.parseInt(order);
610 }
611
612 List list = getSortedList(item);
613
614 if (isInc) {
615 item.setOrderNum(oldnum + 1);
616 item.update();
617
618
619 if ((oldnum + 1) < list.size()) {
620 PickList neighbor = (PickList) list.get(oldnum + 1);
621
622 if ((neighbor != null) &&
623 (neighbor.getOrderNumInt() == (oldnum + 1))) {
624
625 neighbor.setOrderNum(oldnum);
626 neighbor.update();
627 }
628 }
629 } else {
630 item.setOrderNum(oldnum - 1);
631 item.update();
632
633
634 if (((oldnum - 1) >= 0) && (oldnum < list.size())) {
635 PickList neighbor = (PickList) list.get(oldnum - 1);
636
637 if ((neighbor != null) &&
638 (neighbor.getOrderNumInt() == (oldnum - 1))) {
639
640 neighbor.setOrderNum(oldnum);
641 neighbor.update();
642 }
643 }
644 }
645 }
646
647 private List getSortedList(PickList item)
648 throws DBException {
649 PickList all = new PickList();
650 all.setNodeType(item.getNodeType());
651 all.setPickAttribType(item.getPickAttribType());
652
653 List list = all.searchAndRetrieveList();
654 Collections.sort(list);
655
656 return list;
657 }
658
659 private static class ItemNameComparator implements Comparator {
660 /***
661 * @param o1 the first object to be compared.
662 * @param o2 the second object to be compared.
663 * @return a negative integer, zero, or a positive integer as the
664 * first argument is less than, equal to, or greater than the
665 * second.
666 * @throws ClassCastException if the arguments' types prevent them from
667 * being compared by this Comparator.
668 */
669 public int compare(Object o1, Object o2) {
670 int result = 0;
671 PickList item1 = (PickList) o1;
672 PickList item2 = (PickList) o2;
673
674 try {
675 result = item1.getDisplayString().compareTo(item2.getDisplayString());
676 } catch (DBException e) {
677 Logger.getLogger(ItemNameComparator.class).error("Problem comparing picklist items: ", e);
678 }
679
680 return result;
681 }
682 }
683 }