1 13 package com.tonbeller.jpivot.navigator.member; 14 15 import java.util.Collection ; 16 import java.util.Comparator ; 17 import java.util.HashMap ; 18 import java.util.Iterator ; 19 import java.util.Locale ; 20 import java.util.Map ; 21 import java.util.Set ; 22 23 import org.apache.log4j.Logger; 24 import org.w3c.dom.Document ; 25 import org.w3c.dom.Element ; 26 27 import com.tonbeller.jpivot.core.ModelChangeEvent; 28 import com.tonbeller.jpivot.core.ModelChangeListener; 29 import com.tonbeller.jpivot.olap.model.Displayable; 30 import com.tonbeller.jpivot.olap.model.Hierarchy; 31 import com.tonbeller.jpivot.olap.model.Level; 32 import com.tonbeller.jpivot.olap.model.Member; 33 import com.tonbeller.jpivot.olap.model.OlapModel; 34 import com.tonbeller.jpivot.olap.model.OlapUtils; 35 import com.tonbeller.jpivot.olap.navi.MemberDeleter; 36 import com.tonbeller.jpivot.olap.navi.MemberTree; 37 import com.tonbeller.jpivot.ui.Available; 38 import com.tonbeller.tbutils.res.Resources; 39 import com.tonbeller.wcf.component.Component; 40 import com.tonbeller.wcf.controller.Dispatcher; 41 import com.tonbeller.wcf.controller.RequestContext; 42 import com.tonbeller.wcf.controller.RequestListener; 43 import com.tonbeller.wcf.scroller.Scroller; 44 import com.tonbeller.wcf.selection.SelectionModel; 45 import com.tonbeller.wcf.tree.CachingTreeModelDecorator; 46 import com.tonbeller.wcf.tree.DecoratedTreeModel; 47 import com.tonbeller.wcf.tree.DefaultDeleteNodeModel; 48 import com.tonbeller.wcf.tree.DefaultLabelProvider; 49 import com.tonbeller.wcf.tree.DefaultNodeRenderer; 50 import com.tonbeller.wcf.tree.DeleteNodeModel; 51 import com.tonbeller.wcf.tree.EnumBoundedTreeModelDecorator; 52 import com.tonbeller.wcf.tree.GroupingTreeModelDecorator; 53 import com.tonbeller.wcf.tree.LabelProvider; 54 import com.tonbeller.wcf.tree.MutableTreeModelDecorator; 55 import com.tonbeller.wcf.tree.TreeComponent; 56 import com.tonbeller.wcf.tree.TreeModel; 57 import com.tonbeller.wcf.ui.Button; 58 import com.tonbeller.wcf.utils.DomUtils; 59 60 66 public class MemberNavigator extends TreeComponent implements ModelChangeListener, Available { 67 68 public static final String MEMBER_NAVIGATOR_LAZY_FETCH_CHILDREN = "MemberNavigator.lazyFetchChildren"; 69 public static final String MEMBER_NAVIGATOR_EXPAND_SELECTED = "MemberNavigator.expandSelected"; 70 public static final String MEMBER_NAVIGATOR_INITIAL_GROUPING = "MemberNavigator.initialGrouping"; 71 public static final String MEMBER_NAVIGATOR_GROUPING_MEMBER_COUNT = "MemberNavigator.groupingMemberCount"; 72 73 private OlapModel olapModel; 74 private String title; 75 private RequestListener okHandler; 76 private RequestListener cancelHandler; 77 private boolean showSelectNoneButton; 78 private String okButtonId; 79 private String cancelButtonId; 80 private String selectVisibleButtonId; 81 private String selectNoneButtonId; 82 private String enableGroupingButtonId; 83 private String disableGroupingButtonId; 84 private Map models = new HashMap (); 86 private Resources resources; 87 88 private int groupingMemberCount = 12; 89 private boolean initialGrouping = true; 90 private boolean expandSelected = true; 91 private boolean lazyFetchChildren = false; 92 93 99 static class HierarchyArray { 100 101 private Hierarchy[] hiers; 102 103 public HierarchyArray(Hierarchy[] hiers) { 104 this.hiers = hiers; 105 } 106 107 public boolean equals(Object obj) { 108 if (!(obj instanceof HierarchyArray)) 109 return false; 110 HierarchyArray that = (HierarchyArray) obj; 111 if (this.hiers.length != that.hiers.length) 112 return false; 113 for (int i = 0; i < hiers.length; i++) 114 if (!this.hiers[i].equals(that.hiers[i])) 115 return false; 116 return true; 117 } 118 119 public Hierarchy[] getHierarchies() { 120 return hiers; 121 } 122 123 public String getLabel() { 124 if (hiers.length == 0) 125 return ""; if (hiers.length == 1) 127 return hiers[0].getLabel(); 128 StringBuffer sb = new StringBuffer (); 129 for (int i = 0; i < hiers.length; i++) { 130 if (i > 0) 131 sb.append(" / "); sb.append(hiers[i].getLabel()); 133 } 134 return sb.toString(); 135 } 136 137 public int hashCode() { 138 int code = 27; 139 for (int i = 0; i < hiers.length; i++) { 140 code ^= hiers[i].hashCode(); 141 } 142 return code; 143 } 144 145 public void setHierarchies(Hierarchy[] hiers) { 146 this.hiers = hiers; 147 } 148 149 } 150 151 class SelectVisibleHandler implements RequestListener { 152 public void request(RequestContext context) throws Exception { 153 Scroller.enableScroller(context); 154 validate(context); 155 selectVisible(); 156 } 157 } 158 159 class SelectNoneHandler implements RequestListener { 160 public void request(RequestContext context) throws Exception { 161 Scroller.enableScroller(context); 162 validate(context); 163 getSelectionModel().clear(); 164 } 165 } 166 167 class SetGroupingHandler implements RequestListener { 168 boolean grouping; 169 170 SetGroupingHandler(boolean grouping) { 171 this.grouping = grouping; 172 } 173 174 public void request(RequestContext context) throws Exception { 175 validate(context); 176 setGrouping(grouping); 177 } 178 } 179 180 class MutableMemberTreeModelDecorator extends MutableTreeModelDecorator { 181 public MutableMemberTreeModelDecorator(TreeModel decoree) { 182 super(decoree); 183 } 184 185 public MutableMemberTreeModelDecorator(TreeModel decoree, Comparator comp) { 186 super(decoree, comp); 187 } 188 189 public boolean mayMove(Object scope, Object node) { 190 if (!(node instanceof Member)) { return false; } 192 return super.mayMove(scope, node); 193 } 194 } 195 196 private static Logger logger = Logger.getLogger(MemberNavigator.class); 197 198 private DeleteNodeModel deleteModel = new DefaultDeleteNodeModel() { 199 public boolean isDeletable(Object node) { 200 if (olapModel == null) 201 return false; 202 MemberDeleter md = (MemberDeleter) olapModel.getExtension(MemberDeleter.ID); 203 if (md == null) 204 return false; 205 if (node instanceof Member) 206 return md.isDeletable((Member) node); 207 return false; 208 } 209 }; 210 211 public MemberNavigator(String id, Component parent, OlapModel olapModel, 212 RequestListener okHandler, RequestListener cancelHandler) { 213 super(id, parent); 214 logger.info("creating instance: " + this); 215 216 this.olapModel = olapModel; 217 if (olapModel != null) 218 olapModel.addModelChangeListener(this); 219 220 this.okHandler = okHandler; 221 this.cancelHandler = cancelHandler; 222 setNodeRenderer(new DefaultNodeRenderer(labelProvider)); 223 if (id == null) 224 id = DomUtils.randomId(); 225 okButtonId = id + ".ok"; 226 cancelButtonId = id + ".cancel"; 227 selectVisibleButtonId = id + ".selectVisible"; 228 selectNoneButtonId = id + ".selectNone"; 229 enableGroupingButtonId = id + ".enableGrouping"; 230 disableGroupingButtonId = id + ".disableGrouping"; 231 setSelectionModel(new MemberSelectionModel()); 232 setDeleteNodeModel(deleteModel); 233 setCutPasteMode(true); 235 } 236 237 241 public MemberNavigator(String id, Component parent, RequestListener okHandler, 242 RequestListener cancelHandler) { 243 this(id, parent, null, okHandler, cancelHandler); 244 } 245 246 public void setOlapModel(OlapModel newOlapModel) { 247 if (olapModel != null) 248 olapModel.removeModelChangeListener(this); 249 olapModel = newOlapModel; 250 if (olapModel != null) 251 olapModel.addModelChangeListener(this); 252 models.clear(); 253 } 254 255 260 public String getTitle() { 261 return title; 262 } 263 264 public void initialize(RequestContext context) throws Exception { 265 super.initialize(context); 266 267 Dispatcher disp = super.getDispatcher(); 268 disp.addRequestListener(selectVisibleButtonId, null, new SelectVisibleHandler()); 269 disp.addRequestListener(selectNoneButtonId, null, new SelectNoneHandler()); 270 disp.addRequestListener(enableGroupingButtonId, null, new SetGroupingHandler(true)); 271 disp.addRequestListener(disableGroupingButtonId, null, new SetGroupingHandler(false)); 272 disp.addRequestListener(okButtonId, null, okHandler); 273 disp.addRequestListener(cancelButtonId, null, cancelHandler); 274 resources = context.getResources(MemberNavigator.class); 275 276 groupingMemberCount = resources.getOptionalInteger(MEMBER_NAVIGATOR_GROUPING_MEMBER_COUNT, groupingMemberCount); 277 initialGrouping = resources.getOptionalBoolean(MEMBER_NAVIGATOR_INITIAL_GROUPING, initialGrouping); 278 expandSelected = resources.getOptionalBoolean(MEMBER_NAVIGATOR_EXPAND_SELECTED, expandSelected); 279 lazyFetchChildren = resources.getOptionalBoolean(MEMBER_NAVIGATOR_LAZY_FETCH_CHILDREN, lazyFetchChildren); 280 281 String s = context.getRequest().getParameter(MEMBER_NAVIGATOR_LAZY_FETCH_CHILDREN); 283 if (s != null) 284 lazyFetchChildren = Boolean.valueOf(s).booleanValue(); 285 } 286 287 public Element render(RequestContext context, Document factory) throws Exception { 288 if (getModel() == null) 289 throw new IllegalStateException ("must call MemberNavigator.setHierarchy() before rendering"); 290 Element elem = super.render(context, factory); 291 elem.setAttribute("title", title); 292 elem.setAttribute("closeId", cancelButtonId); 293 renderButtons(elem, factory); 294 setError(null); 295 return elem; 296 } 297 298 private void renderButtons(Element parent, Document factory) { 299 Element buttons = factory.createElement("buttons"); 300 parent.appendChild(buttons); 301 appendSelectButton(buttons); 302 appendGroupingButton(buttons); 303 Button.addButton(buttons, okButtonId, resources.getString("MemberNavigator.ok.title")); 304 Button.addButton(buttons, cancelButtonId, resources.getString("MemberNavigator.cancel.title")); 305 } 306 307 private void appendGroupingButton(Element buttons) { 308 if (isGrouping()) { 309 String label = resources.getString("MemberNavigator.disableGrouping.title"); 310 Button.addButton(buttons, disableGroupingButtonId, label); 311 } else { 312 String label = resources.getString("MemberNavigator.enableGrouping.title"); 313 Button.addButton(buttons, enableGroupingButtonId, label); 314 } 315 } 316 317 private void appendSelectButton(Element buttons) { 318 if (getSelectionModel().getMode() == SelectionModel.MULTIPLE_SELECTION) { 320 if (getSelectionModel().isEmpty()) { 321 String label = resources.getString("MemberNavigator.selectVisible.title"); 322 Button.addButton(buttons, selectVisibleButtonId, label); 323 } else { 324 String label = resources.getString("MemberNavigator.selectNone.title"); 325 Button.addButton(buttons, selectNoneButtonId, label); 326 } 327 } 328 else if (showSelectNoneButton) { 330 String label = resources.getString("MemberNavigator.selectNone.title"); 331 Button.addButton(buttons, selectNoneButtonId, label); 332 } 333 } 334 335 public static LabelProvider labelProvider = new DefaultLabelProvider() { 336 public String getLabel(Object node) { 337 if (node instanceof Displayable) 338 return ((Displayable) node).getLabel(); 339 return super.getLabel(node); 340 } 341 }; 342 343 private TreeModelAdapter.OverflowListener overflowListener = new TreeModelAdapter.OverflowListener() { 344 public void overflowOccured() { 345 setError(resources.getString("MemberNavigator.overflowOccurred")); 346 } 347 }; 348 349 355 public void setHierarchies(Hierarchy[] hierarchies, boolean allowChangeOrder) { 356 if (!isAvailable()) 357 return; 358 HierarchyArray hierarchyArray = new HierarchyArray(hierarchies); 359 TreeModel model = (TreeModel) models.get(hierarchyArray); 360 if (model == null) { 361 Locale locale = resources.getLocale(); 363 MemberTree memberTree = (MemberTree) olapModel.getExtension(MemberTree.ID); 364 TreeModelAdapter modelAdapter = new TreeModelAdapter(hierarchies, memberTree, locale); 365 modelAdapter.setOverflowListener(overflowListener); 366 367 for (int i = 0; i < hierarchies.length; i++) { 370 if (OlapUtils.isSingleRecord(hierarchies[i])) { 371 Level[] levels = hierarchies[i].getLevels(); 372 modelAdapter.setNoChildrenLevel(levels[0]); 373 } 374 } 375 376 model = new CachingTreeModelDecorator(modelAdapter); 377 if (lazyFetchChildren) 378 model = new EnumBoundedTreeModelDecorator(model); 379 380 if (hierarchies.length > 0 && !hierarchies[0].getDimension().isMeasure()) { 382 model = new GroupingTreeModelDecorator(labelProvider, model, initialGrouping ? groupingMemberCount : 0); 383 } 384 385 model = new MutableMemberTreeModelDecorator(model); 387 388 models.put(hierarchyArray, model); 390 } 391 392 super.setModel(model); 393 MutableTreeModelDecorator mutableModel = (MutableTreeModelDecorator) findModel(MutableTreeModelDecorator.class); 394 if (mutableModel != null) { 395 mutableModel.setEnableChangeOrder(allowChangeOrder); 396 super.setChangeOrderModel(mutableModel); 397 } 398 this.title = hierarchyArray.getLabel(); 399 } 400 401 public void setHierarchies(Hierarchy[] hiers, boolean allowChangeOrder, MemberSelectionModel selection, Collection deleted) { 402 setHierarchies(hiers, allowChangeOrder); 403 if (lazyFetchChildren) { 404 EnumBoundedTreeModelDecorator boundedModel = (EnumBoundedTreeModelDecorator) findModel(EnumBoundedTreeModelDecorator.class); 405 boundedModel.setVisible(selection.getOrderedSelection()); 406 super.setBounding(boundedModel); 407 } 408 setSelectionModel(selection); 409 if (expandSelected) 410 expandSelected(false); 411 Set set = getDeleteNodeModel().getDeleted(); 412 set.clear(); 413 set.addAll(deleted); 414 } 415 416 419 public void setHierarchy(Hierarchy hierarchy, boolean allowChangeOrder) { 420 setHierarchies(new Hierarchy[] { hierarchy}, allowChangeOrder); 421 } 422 423 429 public void setTitle(String title) { 430 this.title = title; 431 } 432 433 public void modelChanged(ModelChangeEvent e) { 434 for (Iterator it = models.values().iterator(); it.hasNext();) { 435 TreeModel model = (TreeModel) it.next(); 436 TreeModelAdapter tma = (TreeModelAdapter) findModel(model, TreeModelAdapter.class); 437 tma.modelChanged(); 438 } 439 } 440 441 public void structureChanged(ModelChangeEvent e) { 442 logger.info("cleaning up"); 444 models.clear(); 445 super.setModel(null); 446 super.getSelectionModel().clear(); 447 } 448 449 452 public boolean isShowSelectNoneButton() { 453 return showSelectNoneButton; 454 } 455 456 459 public void setShowSelectNoneButton(boolean b) { 460 showSelectNoneButton = b; 461 } 462 463 467 public int getGroupingMemberCount() { 468 return groupingMemberCount; 469 } 470 471 475 public void setGroupingMemberCount(int groupingMemberCount) { 476 this.groupingMemberCount = groupingMemberCount; 477 } 478 479 public boolean isGrouping() { 480 GroupingTreeModelDecorator groupingTreeModel = (GroupingTreeModelDecorator) findModel(GroupingTreeModelDecorator.class); 481 if (groupingTreeModel != null) 482 return groupingTreeModel.getLimit() > 0; 483 return false; 484 } 485 486 public void setGrouping(boolean b) { 487 GroupingTreeModelDecorator groupingTreeModel = (GroupingTreeModelDecorator) findModel(GroupingTreeModelDecorator.class); 488 if (groupingTreeModel != null) 489 groupingTreeModel.setLimit(b ? groupingMemberCount : 0); 490 } 491 492 private TreeModel findModel(Class clazz) { 493 return findModel(getModel(), clazz); 494 } 495 496 private TreeModel findModel(TreeModel tm, Class clazz) { 497 while (true) { 498 if (tm == null) 499 return null; 500 if (clazz.isAssignableFrom(tm.getClass())) 501 return tm; 502 if (!(tm instanceof DecoratedTreeModel)) 503 return null; 504 tm = ((DecoratedTreeModel) tm).getDecoree(); 505 } 506 } 507 508 512 public boolean isAvailable() { 513 return olapModel.getExtension(MemberTree.ID) != null; 514 } 515 516 public void setVisible(boolean b) { 517 if (!isAvailable()) 518 b = false; 519 super.setVisible(b); 520 } 521 522 public boolean isExpandSelected() { 523 return expandSelected; 524 } 525 526 public void setExpandSelected(boolean expandSelected) { 527 this.expandSelected = expandSelected; 528 } 529 530 public boolean isLazyFetchChildren() { 531 return lazyFetchChildren; 532 } 533 534 public void setLazyFetchChildren(boolean lazyFetchChildren) { 535 this.lazyFetchChildren = lazyFetchChildren; 536 } 537 538 539 } | Popular Tags |