1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.primefaces.extensions.component.sheet;
23
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Locale;
33 import java.util.Map;
34 import java.util.Map.Entry;
35 import java.util.Set;
36 import java.util.concurrent.ConcurrentHashMap;
37
38 import javax.el.ELContext;
39 import javax.el.ValueExpression;
40 import javax.faces.FacesException;
41 import javax.faces.application.FacesMessage;
42 import javax.faces.application.ResourceDependency;
43 import javax.faces.component.UIComponent;
44 import javax.faces.context.FacesContext;
45 import javax.faces.convert.Converter;
46 import javax.faces.convert.ConverterException;
47 import javax.faces.event.AjaxBehaviorEvent;
48 import javax.faces.event.FacesEvent;
49
50 import org.primefaces.PrimeFaces;
51 import org.primefaces.extensions.event.SheetEvent;
52 import org.primefaces.extensions.model.sheet.SheetRowColIndex;
53 import org.primefaces.extensions.model.sheet.SheetUpdate;
54 import org.primefaces.extensions.util.ExtLangUtils;
55 import org.primefaces.extensions.util.JavascriptVarBuilder;
56 import org.primefaces.model.SortMeta;
57 import org.primefaces.model.SortOrder;
58 import org.primefaces.util.ComponentUtils;
59 import org.primefaces.util.Constants;
60 import org.primefaces.util.LangUtils;
61
62
63
64
65
66
67
68 @ResourceDependency(library = "primefaces", name = "components.css")
69 @ResourceDependency(library = "primefaces", name = "jquery/jquery.js")
70 @ResourceDependency(library = "primefaces", name = "core.js")
71 @ResourceDependency(library = "primefaces", name = "components.js")
72 @ResourceDependency(library = "primefaces-extensions", name = "primefaces-extensions.js")
73 @ResourceDependency(library = "primefaces-extensions", target = "head", name = "sheet/sheet.css")
74 @ResourceDependency(library = "primefaces-extensions", name = "sheet/sheet.js")
75 public class Sheet extends SheetBase {
76
77 public static final String EVENT_CELL_SELECT = "cellSelect";
78 public static final String EVENT_CHANGE = "change";
79 public static final String EVENT_SORT = "sort";
80 public static final String EVENT_FILTER = "filter";
81 public static final String EVENT_COLUMN_SELECT = "columnSelect";
82 public static final String EVENT_ROW_SELECT = "rowSelect";
83
84 public static final String COMPONENT_TYPE = "org.primefaces.extensions.component.Sheet";
85
86 private static final Collection<String> EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList(EVENT_CHANGE,
87 EVENT_CELL_SELECT, EVENT_SORT, EVENT_FILTER, EVENT_COLUMN_SELECT, EVENT_ROW_SELECT));
88
89
90
91
92 private List<SheetColumn> columns;
93
94
95
96
97 private List<SheetInvalidUpdate> invalidUpdates;
98
99
100
101
102 private final Map<SheetRowColIndex, String> submittedValues = new ConcurrentHashMap<>();
103
104
105
106
107 private final Map<SheetRowColIndex, Object> localValues = new ConcurrentHashMap<>();
108
109
110
111
112 private String selection;
113
114
115
116
117 private String focusId;
118
119
120
121
122 private final List<SheetUpdate> updates = new ArrayList<>();
123
124
125
126
127
128 private Map<Integer, Integer> columnMapping;
129
130
131
132
133 private Map<String, Object> rowMap;
134
135
136
137
138 private Map<String, Integer> rowNumbers;
139
140 @Override
141 public String getFamily() {
142 return SheetBase.COMPONENT_FAMILY;
143 }
144
145
146
147
148 @Override
149 public Collection<String> getEventNames() {
150 return EVENT_NAMES;
151 }
152
153 @Override
154 public String getDefaultEventName() {
155 return EVENT_CHANGE;
156 }
157
158
159
160
161 @Override
162 public void queueEvent(final FacesEvent event) {
163 final FacesContext fc = FacesContext.getCurrentInstance();
164
165 if (isSelfRequest(fc) && event instanceof AjaxBehaviorEvent) {
166 final AjaxBehaviorEvent behaviorEvent = (AjaxBehaviorEvent) event;
167 final SheetEvent sheetEvent = new SheetEvent(this, behaviorEvent.getBehavior());
168 sheetEvent.setPhaseId(event.getPhaseId());
169 super.queueEvent(sheetEvent);
170 return;
171 }
172
173 super.queueEvent(event);
174 }
175
176 private boolean isSelfRequest(final FacesContext context) {
177 return getClientId(context).equals(context.getExternalContext().getRequestParameterMap()
178 .get(Constants.RequestParams.PARTIAL_SOURCE_PARAM));
179 }
180
181
182
183
184 public List<SheetColumn> getColumns() {
185 if (columns == null) {
186 columns = new ArrayList<>();
187 getColumns(this);
188 }
189 return columns;
190 }
191
192
193
194
195 public List<SheetColumn> getRenderedColumns() {
196 final List<SheetColumn> allColumns = getColumns();
197 final List<SheetColumn> renderedCols = new ArrayList<>(allColumns.size());
198 for (final SheetColumn column : allColumns) {
199 if (column.isRendered()) {
200 renderedCols.add(column);
201 }
202 }
203 return renderedCols;
204 }
205
206
207
208
209 private List<SheetColumn> getColumns(final UIComponent parent) {
210 for (final UIComponent child : parent.getChildren()) {
211 if (child instanceof SheetColumn) {
212 columns.add((SheetColumn) child);
213 }
214 }
215 return columns;
216 }
217
218
219
220
221 public void setColumns(final List<SheetColumn> columns) {
222 this.columns = columns;
223 }
224
225
226
227
228 public List<SheetInvalidUpdate> getInvalidUpdates() {
229 if (invalidUpdates == null) {
230 invalidUpdates = new ArrayList<>();
231 }
232 return invalidUpdates;
233 }
234
235
236
237
238 public void resetSubmitted() {
239 submittedValues.clear();
240 updates.clear();
241 }
242
243
244
245
246 public void resetSort() {
247
248 getStateHelper().put(PropertyKeys.currentSortBy.name(), null);
249
250 final String origSortOrder = (String) getStateHelper().get(PropertyKeys.origSortOrder);
251 if (origSortOrder != null) {
252 setSortOrder(origSortOrder);
253 }
254 }
255
256
257
258
259 public void resetInvalidUpdates() {
260 getInvalidUpdates().clear();
261 }
262
263
264
265
266 public void reset() {
267 resetSubmitted();
268 resetSort();
269 resetInvalidUpdates();
270 localValues.clear();
271 for (final SheetColumn c : getColumns()) {
272 c.setFilterValue(null);
273 }
274 }
275
276
277
278
279 public void setSubmittedValue(final String rowKey, final int col, final String value) {
280 submittedValues.put(new SheetRowColIndex(rowKey, col), value);
281 }
282
283
284
285
286 public String getSubmittedValue(final String rowKey, final int col) {
287 return submittedValues.get(new SheetRowColIndex(rowKey, col));
288 }
289
290
291
292
293 public void setLocalValue(final String rowKey, final int col, final Object value) {
294 final SheetRowColIndex key = new SheetRowColIndex(rowKey, col);
295 if (value != null) {
296 localValues.put(key, value);
297 }
298 else {
299 localValues.put(key, ToBeRemoved.class);
300 }
301 }
302
303
304
305
306 public Object getLocalValue(final String rowKey, final int col) {
307 return localValues.get(new SheetRowColIndex(rowKey, col));
308 }
309
310
311
312
313
314
315
316 public void setRowVar(final FacesContext context, final String rowKey) {
317
318 if (context == null) {
319 return;
320 }
321
322 if (rowKey == null) {
323 context.getExternalContext().getRequestMap().remove(getVar());
324 }
325 else {
326 final Object value = getRowMap().get(rowKey);
327 context.getExternalContext().getRequestMap().put(getVar(), value);
328 }
329 }
330
331 protected Map<String, Object> getRowMap() {
332 if (rowMap == null || rowMap.isEmpty()) {
333 remapRows();
334 }
335 return rowMap;
336 }
337
338
339
340
341 public Object getValueForCell(final FacesContext context, final String rowKey, final int col) {
342
343
344 final SheetRowColIndex index = new SheetRowColIndex(rowKey, col);
345 if (localValues.containsKey(index)) {
346 return localValues.get(index);
347 }
348
349 setRowVar(context, rowKey);
350 final SheetColumn column = getColumns().get(col);
351 final ValueExpression ve = column.getValueExpression("value");
352 if (ve != null) {
353 return ve.getValue(context.getELContext());
354 }
355 else {
356 return column.getValue();
357 }
358 }
359
360
361
362
363 public String getRenderValueForCell(final FacesContext context, final String rowKey, final int col) {
364
365
366
367 final SheetRowColIndex index = new SheetRowColIndex(rowKey, col);
368 if (submittedValues.containsKey(index)) {
369 return submittedValues.get(index);
370 }
371
372 final Object value = getValueForCell(context, rowKey, col);
373 if (value == null) {
374 return null;
375 }
376
377 final SheetColumn column = getColumns().get(col);
378 final Converter<Object> converter = ComponentUtils.getConverter(context, column);
379 if (converter == null) {
380 return value.toString();
381 }
382 else {
383 return converter.getAsString(context, this, value);
384 }
385 }
386
387
388
389
390 protected String getRowHeaderValueAsString(final FacesContext context) {
391 final ValueExpression veRowHeader = getRowHeaderValueExpression();
392 final Object value = veRowHeader.getValue(context.getELContext());
393 if (value == null) {
394 return Constants.EMPTY_STRING;
395 }
396 else {
397 return value.toString();
398 }
399 }
400
401
402
403
404 public List<Object> getSortedValues() {
405 List<Object> filtered = getFilteredValue();
406 if (filtered == null || filtered.isEmpty()) {
407 filtered = sortAndFilter();
408 }
409 return filtered;
410 }
411
412
413
414
415 public int getSortColRenderIndex() {
416
417 String currentSortById = (String) getStateHelper().get(PropertyKeys.currentSortBy.name());
418
419 if (LangUtils.isEmpty(currentSortById)) {
420 final Object sortBy = getStateHelper().eval(PropertyKeys.sortBy.name());
421 if (sortBy instanceof String) {
422 currentSortById = (String) sortBy;
423 }
424 }
425 else {
426 int colIdx = 0;
427 for (final SheetColumn column : getColumns()) {
428 if (!column.isRendered()) {
429 continue;
430 }
431
432 if (currentSortById.equals(column.getId())) {
433 return colIdx;
434 }
435 colIdx++;
436 }
437 }
438
439
440
441 final ValueExpression veSortBy = getValueExpression(PropertyKeys.sortBy.name());
442 if (veSortBy == null) {
443 return -1;
444 }
445
446 final String sortByExp = veSortBy.getExpressionString();
447 int colIdx = 0;
448 for (final SheetColumn column : getColumns()) {
449 if (!column.isRendered()) {
450 continue;
451 }
452
453 final ValueExpression veCol = column.getValueExpression(PropertyKeys.sortBy.name());
454 if (veCol != null && veCol.getExpressionString().equals(sortByExp)) {
455 return colIdx;
456 }
457 colIdx++;
458 }
459 return -1;
460 }
461
462
463
464
465
466
467
468 protected boolean matchesFilter() {
469 for (final SheetColumn col : getColumns()) {
470 final String filterValue = col.getFilterValue();
471 if (LangUtils.isBlank(filterValue)) {
472 continue;
473 }
474
475 final Object filterBy = col.getFilterBy();
476
477 if (filterBy == null) {
478 return false;
479 }
480
481 String filterMatchMode = col.getFilterMatchMode();
482 if (LangUtils.isBlank(filterMatchMode)) {
483 filterMatchMode = "contains";
484 }
485
486
487 final String value = filterBy.toString().toLowerCase();
488 final String filter = filterValue.toLowerCase();
489 switch (filterMatchMode) {
490 case "startsWith":
491 if (!value.startsWith(filter)) {
492 return false;
493 }
494 break;
495 case "endsWith":
496 if (!value.endsWith(filter)) {
497 return false;
498 }
499 break;
500 case "exact":
501 if (!value.equals(filter)) {
502 return false;
503 }
504 break;
505 default:
506
507 if (!value.contains(filter)) {
508 return false;
509 }
510 }
511 }
512 return true;
513 }
514
515
516
517
518 public List<Object> sortAndFilter() {
519 List filteredList = getFilteredValue();
520 if (filteredList == null) {
521 filteredList = new ArrayList();
522 }
523 filteredList.clear();
524 rowMap = new HashMap<>();
525 rowNumbers = new HashMap<>();
526
527 final Collection<?> values = (Collection<?>) getValue();
528 if (values == null || values.isEmpty()) {
529 return filteredList;
530 }
531
532 remapRows();
533
534 final List<SheetColumn> columns = getRenderedColumns();
535 boolean filters = false;
536 for (final SheetColumn col : columns) {
537 if (LangUtils.isNotBlank(col.getFilterValue())) {
538 filters = true;
539 break;
540 }
541 }
542
543 final FacesContext context = FacesContext.getCurrentInstance();
544 final Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
545 final String var = getVar();
546
547 if (filters) {
548
549 for (final Object obj : values) {
550 requestMap.put(var, obj);
551 if (matchesFilter()) {
552 filteredList.add(obj);
553 }
554 }
555 }
556 else {
557 filteredList.addAll(values);
558 }
559
560
561 final int sortByIdx = getSortColRenderIndex();
562 final SheetColumn currentSortByColumn = sortByIdx >= 0 ? columns.get(sortByIdx) : null;
563 final ValueExpression currentSortByVe = currentSortByColumn != null ? currentSortByColumn.getValueExpression(
564 PropertyKeys.sortBy.name()) : null;
565 final ValueExpression veSortBy;
566 if (currentSortByVe != null) {
567 veSortBy = currentSortByVe;
568 }
569 else {
570 veSortBy = getValueExpression(PropertyKeys.sortBy.name());
571 }
572 if (veSortBy != null) {
573 final SortMeta sortMeta = SortMeta.builder().field("field").caseSensitiveSort(isCaseSensitiveSort())
574 .sortBy(veSortBy).order(convertSortOrder())
575 .nullSortOrder(getNullSortOrder()).build();
576 filteredList.sort(new BeanPropertyComparator(var, sortMeta, Locale.ENGLISH));
577 }
578
579
580 remapFilteredList(filteredList);
581 return filteredList;
582 }
583
584
585
586
587 protected void remapFilteredList(final List filteredList) {
588 rowNumbers = new HashMap<>(rowMap.size());
589 final FacesContext context = FacesContext.getCurrentInstance();
590 final Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
591 final String var = getVar();
592 int row = 0;
593 for (final Object value : filteredList) {
594 requestMap.put(var, value);
595 rowNumbers.put(getRowKeyValueAsString(context), Integer.valueOf(row));
596 row++;
597 }
598 requestMap.remove(var);
599 }
600
601
602
603
604 protected void remapRows() {
605 rowMap = new HashMap<>();
606 final FacesContext context = FacesContext.getCurrentInstance();
607 final Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
608 final Collection<?> values = (Collection<?>) getValue();
609 final String var = getVar();
610 for (final Object obj : values) {
611 requestMap.put(var, obj);
612 try {
613 final String key = getRowKeyValueAsString(context);
614 rowMap.put(key, obj);
615 }
616 finally {
617 requestMap.remove(var);
618 }
619 }
620 }
621
622
623
624
625
626
627
628 @Override
629 protected Object getRowKeyValue(final FacesContext context) {
630 final ValueExpression veRowKey = getValueExpression(PropertyKeys.rowKey.name());
631 if (veRowKey == null) {
632 throw new FacesException("RowKey required on sheet!");
633 }
634 final Object value = veRowKey.getValue(context.getELContext());
635 if (value == null) {
636 throw new FacesException("RowKey must resolve to non-null value for updates to work properly");
637 }
638 return value;
639 }
640
641
642
643
644 protected String getRowKeyValueAsString(final Object key) {
645 final String result = key.toString();
646 return "r_" + ExtLangUtils.deleteWhitespace(result);
647 }
648
649
650
651
652 protected String getRowKeyValueAsString(final FacesContext context) {
653 return getRowKeyValueAsString(getRowKeyValue(context));
654 }
655
656
657
658
659 protected SortOrder convertSortOrder() {
660 final String sortOrder = getSortOrder();
661 if (sortOrder == null) {
662 return SortOrder.UNSORTED;
663 }
664 else {
665 return SortOrder.valueOf(sortOrder.toUpperCase(Locale.ENGLISH));
666 }
667 }
668
669
670
671
672
673 @Override
674 public void validate(final FacesContext context) {
675
676
677
678
679 final Iterator<Entry<SheetRowColIndex, String>> entries = submittedValues.entrySet().iterator();
680 final boolean hadBadUpdates = !getInvalidUpdates().isEmpty();
681 getInvalidUpdates().clear();
682 while (entries.hasNext()) {
683 final Entry<SheetRowColIndex, String> entry = entries.next();
684 final SheetColumn column = getColumns().get(entry.getKey().getColIndex());
685 final String newValue = entry.getValue();
686 final String rowKey = entry.getKey().getRowKey();
687 final int col = entry.getKey().getColIndex();
688 setRowVar(context, rowKey);
689
690
691
692 final Converter<Object> converter = ComponentUtils.getConverter(context, column);
693
694
695 Object newValueObj = newValue;
696 if (converter != null) {
697 try {
698 newValueObj = converter.getAsObject(context, this, newValue);
699 }
700 catch (final ConverterException e) {
701
702
703
704 setValid(false);
705 FacesMessage message = e.getFacesMessage();
706 if (message == null) {
707 message = new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), e.getMessage());
708 }
709 context.addMessage(getClientId(context), message);
710
711 final String messageText = message.getDetail();
712 getInvalidUpdates()
713 .add(new SheetInvalidUpdate(getRowKeyValue(context), col, column, newValue,
714 messageText));
715 continue;
716 }
717 }
718
719
720
721 setLocalValue(rowKey, col, newValueObj);
722
723
724 column.setValue(newValueObj);
725 try {
726 column.validate(context);
727 }
728 finally {
729 column.resetValue();
730 }
731
732 entries.remove();
733 }
734 setRowVar(context, null);
735
736 final boolean newBadUpdates = !getInvalidUpdates().isEmpty();
737 final String errorMessage = getErrorMessage();
738
739 if ((hadBadUpdates || newBadUpdates) && context.getPartialViewContext().isPartialRequest()) {
740
741 renderBadUpdateScript();
742 }
743
744 if (newBadUpdates && errorMessage != null) {
745 final FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, errorMessage);
746 context.addMessage(null, message);
747 }
748 }
749
750
751
752
753
754
755 @Override
756 public void updateModel(final FacesContext context) {
757 final Iterator<Entry<SheetRowColIndex, Object>> entries = localValues.entrySet().iterator();
758
759
760 final HashSet<String> dirtyRows = new HashSet<>();
761 while (entries.hasNext()) {
762 final Entry<SheetRowColIndex, Object> entry = entries.next();
763
764 final Object newValue = ToBeRemoved.class.equals(entry.getValue()) ? null : entry.getValue();
765 final String rowKey = entry.getKey().getRowKey();
766 final int col = entry.getKey().getColIndex();
767 final SheetColumn column = getColumns().get(col);
768 setRowVar(context, rowKey);
769 final Object rowVal = rowMap.get(rowKey);
770
771 final ValueExpression ve = column.getValueExpression(PropertyKeys.value.name());
772 final ELContext elContext = context.getELContext();
773 final Object oldValue = ve.getValue(elContext);
774 ve.setValue(elContext, newValue);
775 entries.remove();
776 appendUpdateEvent(getRowKeyValue(context), col, rowVal, oldValue, newValue);
777 dirtyRows.add(rowKey);
778 }
779 setLocalValueSet(false);
780 setRowVar(context, null);
781
782 if (context.getPartialViewContext().isPartialRequest()) {
783 renderRowUpdateScript(context, dirtyRows);
784 }
785 }
786
787
788
789
790 @Override
791 public Object saveState(final FacesContext context) {
792 final Object[] values = new Object[8];
793 values[0] = super.saveState(context);
794 values[1] = submittedValues;
795 values[2] = localValues;
796 values[3] = invalidUpdates;
797 values[4] = columnMapping;
798 values[5] = getFilteredValue();
799 values[6] = rowMap;
800 values[7] = rowNumbers;
801 return values;
802 }
803
804
805
806
807 @Override
808 public void restoreState(final FacesContext context, final Object state) {
809 if (state == null) {
810 return;
811 }
812
813 final Object[] values = (Object[]) state;
814 super.restoreState(context, values[0]);
815 final Object restoredSubmittedValues = values[1];
816 final Object restoredLocalValues = values[2];
817 final Object restoredInvalidUpdates = values[3];
818 final Object restoredColMappings = values[4];
819 final Object restoredSortedList = values[5];
820 final Object restoredRowMap = values[6];
821 final Object restoredRowNumbers = values[7];
822
823 submittedValues.clear();
824 if (restoredSubmittedValues != null) {
825 submittedValues.putAll((Map<SheetRowColIndex, String>) restoredSubmittedValues);
826 }
827
828 localValues.clear();
829 if (restoredLocalValues != null) {
830 localValues.putAll((Map<SheetRowColIndex, Object>) restoredLocalValues);
831 }
832
833 if (restoredInvalidUpdates == null) {
834 getInvalidUpdates().clear();
835 }
836 else {
837 invalidUpdates = (List<SheetInvalidUpdate>) restoredInvalidUpdates;
838 }
839
840 if (restoredColMappings == null) {
841 columnMapping = null;
842 }
843 else {
844 columnMapping = (Map<Integer, Integer>) restoredColMappings;
845 }
846
847 if (restoredSortedList == null) {
848 getFilteredValue().clear();
849 }
850 else {
851 setFilteredValue((List<Object>) restoredSortedList);
852 }
853
854 if (restoredRowMap == null) {
855 rowMap = null;
856 }
857 else {
858 rowMap = (Map<String, Object>) restoredRowMap;
859 }
860
861 if (restoredRowNumbers == null) {
862 rowNumbers = null;
863 }
864 else {
865 rowNumbers = (Map<String, Integer>) restoredRowNumbers;
866 }
867 }
868
869
870
871
872
873
874 public String getSelection() {
875 return selection;
876 }
877
878
879
880
881
882
883 public void setSelection(final String selection) {
884 this.selection = selection;
885 }
886
887
888
889
890
891 @Override
892 public Object getSubmittedValue() {
893 if (submittedValues.isEmpty()) {
894 return null;
895 }
896 else {
897 return submittedValues;
898 }
899 }
900
901
902
903
904
905 @Override
906 public void setSubmittedValue(final Object submittedValue) {
907 submittedValues.clear();
908 if (submittedValue != null) {
909 submittedValues.putAll((Map<SheetRowColIndex, String>) submittedValue);
910 }
911
912 }
913
914
915
916
917
918
919 public List<SheetUpdate> getUpdates() {
920 return updates;
921 }
922
923
924
925
926 public boolean isHasStyledCells() {
927 for (final SheetColumn column : getColumns()) {
928 if (column.getStyleClass() != null) {
929 return true;
930 }
931 }
932 return false;
933 }
934
935
936
937
938
939
940
941 public int getMappedColumn(final int renderCol) {
942 if (columnMapping == null || renderCol == -1) {
943 return renderCol;
944 }
945 else {
946 final Integer result = columnMapping.get(renderCol);
947 if (result == null) {
948 throw new IllegalArgumentException("Invalid index " + renderCol);
949 }
950 return result;
951 }
952 }
953
954
955
956
957 public int getRenderIndexFromRealIdx(final int realIdx) {
958 if (columnMapping == null || realIdx == -1) {
959 return realIdx;
960 }
961
962 for (final Entry<Integer, Integer> entry : columnMapping.entrySet()) {
963 if (entry.getValue().equals(realIdx)) {
964 return entry.getKey();
965 }
966 }
967
968 return realIdx;
969 }
970
971
972
973
974 public void updateColumnMappings() {
975 columnMapping = new HashMap<>();
976 int realIdx = 0;
977 int renderCol = 0;
978 for (final SheetColumn column : getColumns()) {
979 if (column.isRendered()) {
980 columnMapping.put(renderCol, realIdx);
981 renderCol++;
982 }
983 realIdx++;
984 }
985 }
986
987
988
989
990 public int getRowCount() {
991 return getSortedValues().size();
992 }
993
994
995
996
997
998
999 public String getFocusId() {
1000 return focusId;
1001 }
1002
1003
1004
1005
1006
1007
1008 public void setFocusId(final String focusId) {
1009 this.focusId = focusId;
1010 }
1011
1012
1013
1014
1015
1016 public void commitUpdates() {
1017 resetSubmitted();
1018 final FacesContext context = FacesContext.getCurrentInstance();
1019 if (context.getPartialViewContext().isPartialRequest()) {
1020 final StringBuilder eval = new StringBuilder();
1021 final String jsVar = resolveWidgetVar();
1022 eval.append("PF('").append(jsVar).append("')").append(".clearDataInput();");
1023 PrimeFaces.current().executeScript(eval.toString());
1024 }
1025 }
1026
1027
1028
1029
1030 public String getInvalidDataValue() {
1031 final JavascriptVarBuilder vb = new JavascriptVarBuilder(null, true);
1032 for (final SheetInvalidUpdate sheetInvalidUpdate : getInvalidUpdates()) {
1033 final Object rowKey = sheetInvalidUpdate.getInvalidRowKey();
1034 final int col = getRenderIndexFromRealIdx(sheetInvalidUpdate.getInvalidColIndex());
1035 final String rowKeyProperty = getRowKeyValueAsString(rowKey);
1036 vb.appendProperty(rowKeyProperty + "_c" + col,
1037 sheetInvalidUpdate.getInvalidMessage().replace("'", "'"), true);
1038 }
1039 return vb.closeVar().toString();
1040 }
1041
1042
1043
1044
1045
1046
1047
1048 public void renderRowUpdateScript(final FacesContext context, final Set<String> dirtyRows) {
1049 final String jsVar = resolveWidgetVar();
1050 final StringBuilder eval = new StringBuilder();
1051
1052 for (final String rowKey : dirtyRows) {
1053 setRowVar(context, rowKey);
1054 final int rowIndex = rowNumbers.get(rowKey);
1055
1056 final JavascriptVarBuilder jsRow = new JavascriptVarBuilder(null, false);
1057 final JavascriptVarBuilder jsStyle = new JavascriptVarBuilder(null, true);
1058 final JavascriptVarBuilder jsReadOnly = new JavascriptVarBuilder(null, true);
1059 int renderCol = 0;
1060 for (int col = 0; col < getColumns().size(); col++) {
1061 final SheetColumn column = getColumns().get(col);
1062 if (!column.isRendered()) {
1063 continue;
1064 }
1065
1066
1067 final String value = getRenderValueForCell(context, rowKey, col);
1068 jsRow.appendArrayValue(value, true);
1069
1070
1071 final String styleClass = column.getStyleClass();
1072 if (styleClass != null) {
1073 jsStyle.appendRowColProperty(rowIndex, renderCol, styleClass, true);
1074 }
1075
1076
1077 final boolean readOnly = column.isReadonlyCell();
1078 if (readOnly) {
1079 jsReadOnly.appendRowColProperty(rowIndex, renderCol, "true", true);
1080 }
1081 renderCol++;
1082 }
1083 eval.append("PF('").append(jsVar).append("')");
1084 eval.append(".updateData('");
1085 eval.append(rowIndex);
1086 eval.append("',");
1087 eval.append(jsRow.closeVar().toString());
1088 eval.append(",");
1089 eval.append(jsStyle.closeVar().toString());
1090 eval.append(",");
1091 eval.append(jsReadOnly.closeVar().toString());
1092 eval.append(");");
1093 }
1094 eval.append("PF('").append(jsVar).append("')").append(".redraw();");
1095 PrimeFaces.current().executeScript(eval.toString());
1096 }
1097
1098
1099
1100
1101 public void renderBadUpdateScript() {
1102 final String widgetVar = resolveWidgetVar();
1103 final String invalidValue = getInvalidDataValue();
1104 StringBuilder sb = new StringBuilder("PF('" + widgetVar + "')");
1105 sb.append(".cfg.errors=");
1106 sb.append(invalidValue);
1107 sb.append(";");
1108 sb.append("PF('").append(widgetVar).append("')");
1109 sb.append(".ht.render();");
1110 PrimeFaces.current().executeScript(sb.toString());
1111
1112 sb = new StringBuilder();
1113 sb.append("PF('").append(widgetVar).append("')");
1114 sb.append(".sheetDiv.removeClass('ui-state-error')");
1115 if (!getInvalidUpdates().isEmpty()) {
1116 sb.append(".addClass('ui-state-error')");
1117 }
1118 PrimeFaces.current().executeScript(sb.toString());
1119 }
1120
1121
1122
1123
1124 public void appendUpdateEvent(final Object rowKey, final int colIndex, final Object rowData, final Object oldValue,
1125 final Object newValue) {
1126 updates.add(new SheetUpdate(rowKey, colIndex, rowData, oldValue, newValue));
1127 }
1128 }