KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > calipso > reportgenerator > common > HeaderTableModel


1 package com.calipso.reportgenerator.common;
2
3 import javax.swing.table.AbstractTableModel JavaDoc;
4 import java.util.Collection JavaDoc;
5 import java.util.Iterator JavaDoc;
6 import java.util.List JavaDoc;
7 import java.util.Vector JavaDoc;
8
9 /**
10  * Modelo para las tablas de encabezados de filas y columnas
11  */

12
13 public class HeaderTableModel extends AbstractTableModel JavaDoc {
14   public static final int MODE_ROW = 0;
15   public static final int MODE_COLUMN = 1;
16   private DimensionValueNode dimensionValueNode;
17   private boolean withTotals;
18   private int dimensionCount;
19   private int mode;
20   private int rowCount;
21   private List JavaDoc visibleMetrics;
22   private ReportQuery reportQuery;
23   private ReportSpec reportSpec;
24   private int iterations = 0;
25
26   /**
27    * Crea un nuevo modelo inicializandolo para la tabla de encabezados de fila.
28    * @param dimensionValueNode
29    * @param withTotals
30    * @param rowCount
31    * @param reportQuery
32    * @return
33    */

34   public static HeaderTableModel newRowHeaderTableModel(DimensionValueNode dimensionValueNode, boolean withTotals, int rowCount, ReportQuery reportQuery, ReportSpec reportSpec) {
35     return new HeaderTableModel(dimensionValueNode, withTotals, MODE_ROW, rowCount, reportQuery, reportSpec);
36   }
37
38   /**
39    * Crea un nuevo modelo inicializandolo para la tabla de encabezados de columna.
40    * @param dimensionValueNode
41    * @param withTotals
42    * @param rowCount
43    * @param reportQuery
44    * @return
45    */

46   public static HeaderTableModel newColumnHeaderTableModel(DimensionValueNode dimensionValueNode, boolean withTotals, int rowCount, ReportQuery reportQuery, ReportSpec reportSpec) {
47     return new HeaderTableModel(dimensionValueNode, withTotals, MODE_COLUMN, rowCount, reportQuery, reportSpec);
48   }
49
50   /**
51    * Crea e inicializa una nueva instancia.
52    * @param dimensionValueNode
53    * @param withTotals
54    * @param mode
55    * @param rowCount
56    * @param reportQuery
57    */

58
59   protected HeaderTableModel(DimensionValueNode dimensionValueNode, boolean withTotals, int mode, int rowCount, ReportQuery reportQuery, ReportSpec reportSpec) {
60     this.dimensionValueNode = dimensionValueNode;
61     this.withTotals = withTotals;
62     this.dimensionCount = dimensionValueNode.getDimensionCount();
63     this.mode = mode;
64     this.rowCount = rowCount;
65     this.reportQuery = reportQuery;
66     this.reportSpec = reportSpec;
67     initialize();
68   }
69
70   /**
71    * Inicializa la lista de metricas visibles a partir de la ReportQuery
72    */

73   private void initialize() {
74     visibleMetrics = reportQuery.getVisibleMetrics();
75   }
76
77
78   /**
79    * Devuelve la lista de Métricas visibles
80    * @return
81    */

82   public List JavaDoc getVisibleMetrics() {
83     return visibleMetrics;
84   }
85
86   /**
87    * Devuelve la cantidad de métricas visibles
88    * @return
89    */

90   public int getVisibleMetricsCount() {
91     return getVisibleMetrics().size();
92   }
93
94   /**
95    * Devuelve el Nodo raíz del arbol de grupos
96    * @see com.calipso.reportgenerator.common.DimensionValueNode
97    * @see com.calipso.reportgenerator.reportmanager.DimensionValueTreeBuilder
98    * @return
99    */

100   public DimensionValueNode getDimensionValueNode() {
101     return dimensionValueNode;
102   }
103
104   /**
105    * Devuelve verdadero si se deben mostrar los totales
106    * @return
107    */

108   public boolean getWithTotals() {
109     return withTotals;
110   }
111
112   /**
113    * Especifica si se deben mostrar los totales
114    * @param withTotals
115    */

116
117   public void setWithTotals(boolean withTotals) {
118     this.withTotals = withTotals;
119   }
120
121
122   /**
123    * Asigna el nodo raíz del arbol de grupos
124    * @param dimensionValueNode
125    */

126   public void setDimensionValueNode(DimensionValueNode dimensionValueNode) {
127     this.dimensionValueNode = dimensionValueNode;
128   }
129
130   /**
131    * Devuelve la cantidad de dimensiones que agrupan
132    * @return
133    */

134   public int getDimensionCount() {
135     return dimensionCount;
136   }
137
138   /**
139    * Asigna la cantidad de dimensiones que agrupan
140    * @param dimensionCount
141    */

142   public void setDimensionCount(int dimensionCount) {
143     this.dimensionCount = dimensionCount;
144   }
145
146   /**
147    * Devuelve la cantidad de renglones que tendrá la tabla, su valor depennde del modo en que esté trabajando (fila o
148    * columna)
149    * @return
150    */

151   public int getRowCount() {
152     int count = 0;
153     switch (mode) {
154       case MODE_ROW:
155         return Math.max(doGetRowCount(), 1);
156       case MODE_COLUMN:
157         count = doGetColumnCount();
158         if ((getVisibleMetricsCount() > 1) || (count == 0)) {
159           count++;
160         }
161         return count;
162     }
163     return count;
164   }
165
166   /**
167    * Devuelve la cantidad de columnas que tendrá la tabla, su valor depennde del modo en que esté trabajando (fila o
168    * columna)
169    */

170
171   public int getColumnCount() {
172     switch (mode) {
173       case MODE_ROW:
174         return Math.max(doGetColumnCount(), 1);
175       case MODE_COLUMN:
176         return doGetRowCount();
177     }
178     return 0;
179   }
180
181   /**
182    * devuelve la cantidad de nodos del ultimo nivel del arbol dependiendo del modo se utiliza para obtener la cantidad de
183    * filas o la cantidad de columnas del arbol
184    * @return
185    */

186   public int doGetRowCount() {
187     return rowCount;
188   }
189
190   /**
191    * Asigna la cantidad de nodos del ultimo nivel, este valor se setea siempre que se redibuje la tabla porque si hay grupos
192    * colapsados este valor puede variar.
193    * @param value
194    */

195   public void setRowCount(int value) {
196     rowCount = value;
197   }
198
199   /**
200    * Devuelve la cantidad de dimensiones que agrupan, se utiliza para conocer la cantidad de filas o columnas de la tabla
201    * dependiendo del modo
202    * @return
203    */

204   public int doGetColumnCount() {
205     int count = getDimensionCount();
206     return count;
207   }
208
209   /**
210    * Metodo no implemntado de <code>AbstractTableModel</code>.
211    * @param rowIndex
212    * @param columnIndex
213    * @return
214    */

215   public Object JavaDoc getValueAt(int rowIndex, int columnIndex) {
216     return null;
217   }
218
219   /**
220    * Devuelve el indice de una columna correspondiente a un nodo
221    * @param node
222    * @return
223    */

224   public int getNodeColumn(DimensionValueNode node) {
225     return node.getDimesionIndex();
226   }
227
228   /**
229    * Devuelve un array de celdas que deben dibujarse para representar un nodo (si el nodo tiene subnodos, requerirá
230    * más de una celda para su representación)
231    * @param node
232    * @return
233    */

234   public int[][] getNodeCells(DimensionValueNode node, int row, int size) {
235     if (node.getCollapsed()) {
236       return getCollapsedNodeCells(node, row);
237     }
238     else {
239       return getExpandedNodeCells(node, row, size);
240     }
241   }
242
243   /**
244    * Devuelve un array de celdas que deben dibujarse para representar un nodo colapsado
245    * @param node
246    * @param row
247    * @return
248    */

249   private int[][] getCollapsedNodeCells(DimensionValueNode node, int row) {
250     int xSize = getDimensionCount() - (node.getDimesionIndex());
251     int[][] cells = new int[xSize][2];
252     for (int i = 0; i < xSize; i++) {
253       cells[i] = newCell(row, node.getDimesionIndex() + i);
254     }
255     return cells;
256   }
257
258   /**
259    * Devuelve un array de celdas que deben dibujarse para representar un nodo expandido
260    * @param node
261    * @param row
262    * @param size
263    * @return
264    */

265   private int[][] getExpandedNodeCells(DimensionValueNode node, int row, int size) {
266     int xSize = size;
267     int nodeDimIndex = node.getDimesionIndex();
268     int[][] cells = new int[xSize][2];
269     for (int i = 0; i < xSize; i++) {
270       cells[i] = newCell(row + i, nodeDimIndex);
271     }
272     return cells;
273   }
274
275
276   /**
277    * Devuelve un array de celdas que deben dibujarse para representar un nodo como total
278    * @param node
279    * @param lastRow
280    * @return
281    */

282   public int[][] getTotalNodeCells(DimensionValueNode node, int lastRow) {
283     int size = getDimensionCount() - (node.getDimesionIndex() + 1);
284     int[][] cells = new int[size][2];
285     for (int i = 0; i < size; i++) {
286       cells[i] = newCell(lastRow, node.getDimesionIndex() + 1 + i);
287     }
288     return cells;
289   }
290
291   /**
292    * Crea una array de dos posiciones donde la primera es el indice de fila y la segunda es el indice de columna
293    * Dependiendo del modo, se decide a que posición del array se asigna cada parámetro (el resto de la clase trabaja
294    * como si siempre el modo fuera MODE_ROW y con este método se invierten las coordenadas en el caso de modo MODE_COLUMN
295    * @param row
296    * @param col
297    * @return
298    */

299   public int[] newCell(int row, int col) {
300     int[] cell = new int[2];
301     switch (mode) {
302       case MODE_ROW:
303         cell[0] = row;
304         cell[1] = col;
305         break;
306       case MODE_COLUMN:
307         cell[0] = col;
308         cell[1] = row;
309         break;
310     }
311     return cell;
312   }
313
314   /**
315    * Devuelve el modo en que se dibuja la tabla
316    * @return
317    */

318   public int getMode() {
319     return mode;
320   }
321
322   /**
323    * Asigna el modo en que se dibuja la tabla
324    * @param mode
325    */

326   public void setMode(int mode) {
327     this.mode = mode;
328   }
329
330   /**
331    * Devuelve verdadero si el modo es colapsable (esto es si es un nodo que agrupa subnodos)
332    * @param node
333    * @return
334    */

335   public boolean getNodeIsCollapsable(DimensionValueNode node) {
336     return node.getDimesionIndex() < getDimensionValueNode().getDimensionCount() - 1;
337   }
338
339   /**
340    * @param row
341    * @param col
342    * @return Devuelve true si el nodo es colapsable y se logró colapsar o expandir
343    */

344
345   public boolean changeNodeState(int row, int col) {
346     DimensionValueNode root = getDimensionValueNode();
347     int internalRow;
348     int internalCol;
349     if (mode == HeaderTableModel.MODE_ROW) {
350       internalRow = row;
351       internalCol = col;
352     }
353     else {
354       internalRow = col;
355       internalCol = row;
356     }
357     DimensionValueNode node = findCollapsableNode(root, internalRow, internalCol, new RowIndexCarrier());
358     if (node != null) {
359       node.changeDimensionValueNodeState();
360     }
361     return node != null;
362   }
363
364   /**
365    * Clase interna que se utiliza para acumular el valor del ultimo indice recorrido en metodos recursivos
366    */

367   private class RowIndexCarrier {
368     private int index = 0;
369
370     public int getIndex() {
371       return index;
372     }
373
374     public void inc(int value) {
375       index += value;
376     }
377   }
378
379   /**
380    * Devuelve el nodo colapsable correspondiente a las coordenadas de fila y columna que se reciben como parámetro
381    * @param node
382    * @param row
383    * @param col
384    * @param carrier
385    * @return
386    */

387   private DimensionValueNode findCollapsableNode(DimensionValueNode node, int row, int col, RowIndexCarrier carrier) {
388     DimensionValueNode resultNode = null;
389     Iterator JavaDoc iterator = (node.getSubNodesList()).iterator();
390     if (carrier.getIndex() == row && node.getDimesionIndex() == col) {
391       resultNode = node;
392     }
393     else {
394       if (!node.getCollapsed()) {
395         while (resultNode == null && iterator.hasNext()) {
396           DimensionValueNode subNode = (DimensionValueNode) iterator.next();
397           if (carrier.getIndex() <= row && subNode.getDimesionIndex() < getDimensionCount() - 1) {
398             resultNode = findCollapsableNode(subNode, row, col, carrier);
399           }
400           if (subNode.getDimesionIndex() == getDimensionCount() - 1) {
401             carrier.inc(getCarrierIncrement());
402           }
403         }
404       }
405       if (node.getCollapsed() || getWithTotals()) {
406         carrier.inc(getCarrierIncrement());
407       }
408     }
409     return resultNode;
410   }
411
412   private int getCarrierIncrement() {
413     if (getMode() == MODE_ROW) {
414       return 1;
415     }
416     else {
417       return getVisibleMetricsCount();
418     }
419   }
420
421   /**
422    * Devuelve los valores de las dimensiones para un indice de fila (o columna dependiendo del modo)
423    * @param index
424    * @return
425    */

426   public Object JavaDoc[] getValueFrom(int index) {
427     if (mode == MODE_ROW || getVisibleMetricsCount() == 1) {
428       DimensionValueNode node = (DimensionValueNode) getDimensionValueNode().getAllSubNodes().get(new Integer JavaDoc(index));
429       return getNodeValues(node);
430     }
431     else {
432       int metricIndex = index % getVisibleMetricsCount();
433       int actualIndex = index - metricIndex;
434       DimensionValueNode node = (DimensionValueNode) getDimensionValueNode().getAllSubNodes().get(new Integer JavaDoc(actualIndex));
435       if (node == null && actualIndex == 0) {
436         node = getDimensionValueNode();
437       }
438       return getNodeValues(node, metricIndex);
439     }
440   }
441
442   public Object JavaDoc[] getValuesFrom(int index) {
443     DimensionValueNode root = getDimensionValueNode();
444     return getValuesFrom(root, index, new IntegerExt(0));
445   }
446
447   public Object JavaDoc[] getValuesFrom(DimensionValueNode node, int wantedIndex, IntegerExt integer) {
448     boolean found = false;
449     Object JavaDoc[] returnVal = null;
450     if (node.getSubNodesList().size() == 0) {
451       if (integer.getCurrentValue() == wantedIndex) {
452         returnVal = getValuesFrom(node);
453         return returnVal;
454       }
455       else {
456         integer.sumValue(1);
457       }
458     }
459     else {
460       Collection JavaDoc nodes = node.getSubNodesList();
461       Iterator JavaDoc iterator = nodes.iterator();
462       while (iterator.hasNext() && !found) {
463         DimensionValueNode currentNode = (DimensionValueNode) iterator.next();
464         returnVal = getValuesFrom(currentNode, wantedIndex, integer);
465         if (returnVal != null) {
466           found = true;
467         }
468       }
469     }
470     return returnVal;
471   }
472
473   private Object JavaDoc[] getValuesFrom(DimensionValueNode leaf) {
474     Object JavaDoc returnVal [];
475     if (mode == MODE_ROW) {
476       returnVal = new Object JavaDoc[getColumnCount()];
477       fillArray(returnVal, leaf, returnVal.length - 1, "ROWS");
478     }
479     else {
480       returnVal = new Object JavaDoc[getRowCount()];
481       fillArray(returnVal, leaf, returnVal.length - 1, "COLUMNS");
482     }
483     return returnVal;
484   }
485
486   private void fillArray(Object JavaDoc[] returnVal, DimensionValueNode node, int i, String JavaDoc mode) {
487     if (!node.getValue().toString().equalsIgnoreCase(mode)) {
488       returnVal[i] = node.getValue().toString();
489       fillArray(returnVal, node.getParentNode(), i - 1, mode);
490     }
491   }
492
493   /**
494    * Devuelve el título de una métrica segun el indice en que aparecen el la ReportQuery
495    * @param index
496    * @return
497    */

498   public String JavaDoc getMetricCaption(int index) {
499     QueryMetric metric = (QueryMetric) reportQuery.getVisibleMetrics().get(index);
500     return reportSpec.getMetricFromName(metric.getName()).getCaption();
501   }
502
503   /**
504    * Devuelve los valores de las dimensiones para un indice de fila (o columna dependiendo del modo), para el caso en que
505    * hay mas de una métrica, se debe especificar el nombre de la métrica además de los valores de dimensiones
506    * @param node
507    * @param metricIndex
508    * @return
509    */

510   private Object JavaDoc[] getNodeValues(DimensionValueNode node, int metricIndex) {
511     Object JavaDoc[] auxValues = getNodeValues(node);
512     Object JavaDoc[] result = new Object JavaDoc[auxValues.length + 1];
513     System.arraycopy(auxValues, 0, result, 0, auxValues.length);
514     result[result.length - 1] = getMetricCaption(metricIndex);
515     return result;
516   }
517
518   /**
519    * Devuelve los valores de las dimensiones para un indice de fila (o columna dependiendo del modo)
520    * @param node
521    * @return
522    */

523   private Object JavaDoc[] getNodeValues(DimensionValueNode node) {
524     Object JavaDoc[] values = new Object JavaDoc[getDimensionCount()];
525     DimensionValueNode currentNode = node;
526     while ((currentNode != null) && currentNode.getDimesionIndex() >= 0) {
527       values[currentNode.getDimesionIndex()] = currentNode.getValue().toString();
528       currentNode = currentNode.getParentNode();
529     }
530     return values;
531   }
532
533   /**
534    * Obtiene el FooterCaption para la dimension.
535    * @param dimesionIndex
536    * @return
537    */

538   public String JavaDoc getGroupFooterCaption(int dimesionIndex) {
539     if (dimesionIndex >= 0) {
540       List JavaDoc dimensions;
541       if (getMode() == MODE_COLUMN) {
542         dimensions = reportQuery.getColumnDimensions();
543       }
544       else {
545         dimensions = reportQuery.getRowDimensions();
546       }
547       QueryDimension dimension = (QueryDimension) dimensions.get(dimesionIndex);
548       String JavaDoc result = reportSpec.getDimensionFromName(dimension.getName()).getGroupFooterCaption();
549       if ((result!=null)&&(result != "")) return result;
550     }
551     return LanguageTraslator.traslate("358");
552   }
553
554   /**
555    * Calcula si una row es total
556    * @param row
557    * @return
558    */

559   public boolean isTotalRow(int row) {
560     if(!reportQuery.isVisibleTotals()){
561       return false;
562     }
563     Vector JavaDoc totals = new Vector JavaDoc();
564     fillTotalRows(totals, this.getDimensionValueNode());
565     iterations = 0;
566     return totals.contains(new Integer JavaDoc(row));
567   }
568
569   /**
570    * Calcula si una columna es total
571    * @param col
572    * @return
573    */

574   public boolean isTotalCol(int col) {
575     if(!reportQuery.isVisibleTotals()){
576       return false;
577     }
578     Vector JavaDoc totals = new Vector JavaDoc();
579     fillTotalCols(totals, this.getDimensionValueNode());
580     iterations = 0;
581     return totals.contains(new Integer JavaDoc(col));
582   }
583
584   /**
585    * Llena un Vector con las columnas que son totales
586    * @param totals
587    * @param node
588    */

589   public void fillTotalCols(Vector JavaDoc totals, DimensionValueNode node) {
590     if (node.getSubNodesList().isEmpty()) {
591       iterations += getVisibleMetricsCount();
592       return;
593     }
594     Iterator JavaDoc iterator = node.getSubNodesList().iterator();
595     while (iterator.hasNext()) {
596       DimensionValueNode current = (DimensionValueNode) iterator.next();
597       fillTotalCols(totals, current);
598     }
599     for (int i = 0; i < getVisibleMetricsCount(); i++) {
600       totals.add(new Integer JavaDoc(iterations));
601       iterations++;
602     }
603   }
604
605   /**
606    * Calcula las filas totales en base al nodo ROW y llena un vector con los resultados
607    * @param totals
608    * @param node
609    */

610   public void fillTotalRows(Vector JavaDoc totals, DimensionValueNode node) {
611     if (node.getSubNodesList().isEmpty()) {
612       iterations++;
613       return;
614     }
615     Iterator JavaDoc iterator = node.getSubNodesList().iterator();
616     while (iterator.hasNext()) {
617       DimensionValueNode current = (DimensionValueNode) iterator.next();
618       fillTotalRows(totals, current);
619     }
620     totals.add(new Integer JavaDoc(iterations));
621     iterations++;
622   }
623
624 }
Popular Tags