DClick

Acentuação no Sort do DataGrid


Continuando o caso do Sort no DataGrid, que no post anterior em http://blog.dclick.com.br/2007/06/02/alterando-o-sort-default-do-datagrid-de-case-sensitive-para-case-insensitive/
onde foi relatado como se utilizar a propriedade caseInsensitive, chegamos agora no problema de tratamento de ordenação de palavras acentuadas com palavras não acentuadas. O sort executado, não consegue identificar, a partir do locale de países de língua portuguesa, que palavras acentuadas devem ser tratadas da mesma maneira que palavras sem acentuação para o caso de ordenação. Ou seja, árvore é igual a arvore quando mostramos em ordem num grid.

A solução para este caso, reside no fato da classe SortField ser responsável pela definição de qual função de comparação será usada em objetos do tipo string, para identificar a ordem. Assim com a simples extensão desta classe (ExtendedSortField), conseguimos indicar qual função de ordenação de strings deve ser usada internamente para o resultado esperado.

Actionscript:
  1. package sort
  2. {
  3. import mx.collections.SortField;
  4. import mx.utils.ObjectUtil;
  5. import mx.core.mx_internal;
  6.  
  7. use namespace mx_internal;
  8.  
  9. public class ExtendedSortField extends SortField
  10. {
  11.  
  12. override mx_internal function initCompare(obj:Object):void
  13. {
  14. var isStringField:Boolean = false;
  15.  
  16. // if the compare function is not already set then we can set it
  17. if (!usingCustomCompareFunction)
  18. {
  19. if (!numeric)
  20. {
  21. if (caseInsensitive)
  22. isStringField = true;
  23. else
  24. {
  25. // we need to introspect the data a little bit
  26. var value:Object;
  27. if (name)
  28. {
  29. try
  30. {
  31. value = obj[name];
  32. }
  33. catch (error:Error)
  34. {
  35. }
  36. }
  37. //this needs to be an == null check because !value will return true
  38. //where value == 0 or value == false
  39. if (value == null)
  40. {
  41. value = obj;
  42. }
  43.  
  44. var typ:String = typeof(value);
  45. switch (typ)
  46. {
  47. case "string":
  48. isStringField = true;
  49. break;
  50. case "object":
  51. if (!(value is Date))
  52. {
  53. isStringField = true;
  54. var test:String;
  55. try
  56. {
  57. test = value.toString();
  58. }
  59. catch (error2:Error) {}
  60. if (!test || test == "[object Object]")
  61. {
  62. isStringField = false;
  63. }
  64. }
  65. break;
  66. }
  67. }  // else
  68. }
  69. } // if
  70.  
  71. if (isStringField)
  72. {
  73. compareFunction = stringCompare;
  74. }
  75.  
  76. super.initCompare(obj);
  77. }
  78.  
  79. /**
  80. * Pull the strings from the objects and call the implementation.
  81. */
  82. private function stringCompare(a:Object, b:Object):int
  83. {
  84. var fa:String;
  85. try
  86. {
  87. fa = name == null ? String(a) : String(a[name]);
  88. }
  89. catch (error:Error)
  90. {
  91. }
  92.  
  93. var fb:String;
  94. try
  95. {
  96. fb = name == null ? String(b) : String(b[name]);
  97. }
  98. catch (error:Error)
  99. {
  100. }
  101.  
  102. var sa:String = "";
  103. if (fa != null)
  104. {
  105. sa = String(mx.utils.ObjectUtil.copy(fa));
  106. sa = removeSpecialChars(sa);
  107. }
  108.  
  109. var sb:String = "";
  110. if (fb != null)
  111. {
  112. sb = String(mx.utils.ObjectUtil.copy(fb));
  113. sb = removeSpecialChars(sb);
  114. }
  115.  
  116. return mx.utils.ObjectUtil.stringCompare(sa, sb, caseInsensitive);
  117. }
  118.  
  119. /**
  120. *
  121. * @param value String de entrada que será modificada de acorde com a tabela ASCII extendida
  122. * @return String alterada
  123. *
  124. */
  125. public static function removeSpecialChars(value:String):String
  126. {
  127. var patternTable:Object = new Object();
  128. patternTable["A"] = /À|Á|Â|Ã|Ä|Å/g;
  129. patternTable["E"] = /È|É|Ê|Ë/g;
  130. patternTable["I"] = /Ì|Í|Î|Ï/g;
  131. patternTable["O"] = /Ò|Ó|Ô|Õ|Ö/g;
  132. patternTable["U"] = /Ù|Ú|Û|Ü/g;
  133. patternTable["a"] = /à|á|â|ã|ä/g;
  134. patternTable["e"] = /è|é|ê|ë/g;
  135. patternTable["i"] = /ì|í|î|ï/g;
  136. patternTable["o"] = /ò|ó|ô|õ|ö/g;
  137. patternTable["u"] = /ù|ú|û|ü/g;
  138. patternTable["C"] = /Ç/g;
  139. patternTable["c"] = /ç/g;
  140. patternTable["N"] = /Ñ/g;
  141. patternTable["n"] = /ñ/g;
  142.  
  143. var result:String = value;
  144. for (var letter:String in patternTable)
  145. {
  146. result = result.replace(patternTable[letter], letter);
  147. }
  148. return result;
  149. }
  150. }
  151. }

Mas para que isso funcione, devemos antes preparar o sort do dataProvider do DataGrid, adicionando neste, conforme o usuário interage com a coluna em questão, os fields do tipo de nossa classe extendida (ExtendedSortField).

Estendendo também a classe DataGrid, adicionamos no seu construtor um listener para o evento DataGridEvent.HEADER_RELEASE.

Actionscript:
  1. public function ExtendedDataGrid()
  2. {
  3. // Como o listener foi criado com a mesma prioridade do listener da classe mãe,
  4. // este deve ser adicionado ANTES da adição do mesmo da classe mãe,
  5. // para que esta implementação seja executada da mesma forma, ANTES.
  6. addEventListener(DataGridEvent.HEADER_RELEASE,
  7. headerReleaseHandler,
  8. false, EventPriority.DEFAULT_HANDLER, true);
  9.  
  10. super();
  11. }

No handler desse evento, preparamos o dataProvider com o sort adequado.

Actionscript:
  1. private function headerReleaseHandler(event:DataGridEvent):void
  2. {
  3. if (!event.isDefaultPrevented())
  4. {
  5. prepareGridColumnSort(this, dataProvider as ICollectionView,
  6.  
  7. event.dataField, !sortCaseSensitive);
  8. }
  9. }
  10.  
  11. /**
  12. *
  13. * @param grid Instância do DataGrid que será preparado para utilização do   caseInsensitive e Numeric
  14. * @param gridDataProvider DataProvider do DataGrid, que será observado para criação da classe Sort
  15. * @return DataProvider modificado, contendo a classe Sort e SortField definida para cada DataGridColumn do DataGrid
  16. *
  17. */
  18. private function prepareGridColumnSort(grid:DataGrid,    gridDataProvider:ICollectionView, dataField:String, caseInsensitive:Boolean=true):void
  19. {
  20. var sort:Sort;
  21. var field:SortField;
  22. var column:DataGridColumn;
  23. var bFieldFound:Boolean = false;
  24.  
  25. if (gridDataProvider && dataField)
  26. {
  27. sort = gridDataProvider.sort;
  28.  
  29. if (sort == null)
  30. {
  31. sort = new Sort();
  32. }
  33.  
  34. for each (field in sort.fields)
  35. {
  36. if (field.name == dataField)
  37. {
  38. field.caseInsensitive = caseInsensitive;
  39. bFieldFound = true;
  40. break;
  41. }
  42. }
  43.  
  44. if (!bFieldFound)
  45. {
  46. for each (column in grid.columns)
  47. {
  48. if (dataField == column.dataField)
  49. {
  50. field = new ExtendedSortField();
  51. field.name = column.dataField;
  52. field.descending = column.sortDescending;
  53. field.caseInsensitive = caseInsensitive;
  54. if (column.sortCompareFunction != null)
  55. {
  56. field.compareFunction = column.sortCompareFunction;
  57. }
  58. field.numeric = isDataFieldNumber(gridDataProvider, dataField);
  59. sort.fields = [field];
  60. break;
  61. }
  62. }
  63. }
  64.  
  65. gridDataProvider.sort = sort;
  66. }
  67. }
  68.  
  69. /**
  70. *
  71. * @param gridDataProvider Instância do DataGrid no qual será testado o campo do tipo Number
  72. * @param dataField Nome do campo que será testado
  73. * @return Resultado boolean indicando se é Number ou não
  74. *
  75. */
  76. private function isDataFieldNumber(gridDataProvider:ICollectionView, dataField:String):Boolean
  77. {
  78. if (gridDataProvider && gridDataProvider.length > 0 && dataField)
  79. {
  80. var obj:Object = gridDataProvider[0];
  81. if (obj.hasOwnProperty(dataField) && ((obj[dataField] is Number) || (obj[dataField] is uint) || (obj[dataField] is int)))
  82. {
  83. return true;
  84. }
  85. }
  86. return false;
  87. }

Após estes passos, toda vez que o usuário clicar no cabeçalho de uma coluna, este evento será capturado primeiro pela nossa função handler que irá preparar o sort do dataProvider do DataGrid com nossa classe ExtendedSortField.

Esta por sua vez, sabe como comparar valores string acentuadas, retirando os caracteres especiais antes de efetuar a comparação.

Por Marcello Rego em 18/October/2007 | Comentar | Trackback


No Translations

Um comentário para “Acentuação no Sort do DataGrid”


Show de bola!!!

Adicionar comentário

(requerido)
(requerido, não será publicado)