374 // by calling super.startEdit().
375 super.startEdit();
376
377 // Inform the TreeView of the edit starting.
378 if (tree != null) {
379 tree.fireEvent(new TreeView.EditEvent<T>(tree,
380 TreeView.<T>editStartEvent(),
381 getTreeItem(),
382 getItem(),
383 null));
384
385 tree.requestFocus();
386 }
387 }
388
389 /** {@inheritDoc} */
390 @Override public void commitEdit(T newValue) {
391 if (! isEditing()) return;
392 final TreeItem<T> treeItem = getTreeItem();
393 final TreeView<T> tree = getTreeView();
394 if (tree != null) {
395 // Inform the TreeView of the edit being ready to be committed.
396 tree.fireEvent(new TreeView.EditEvent<T>(tree,
397 TreeView.<T>editCommitEvent(),
398 treeItem,
399 getItem(),
400 newValue));
401 }
402
403 // inform parent classes of the commit, so that they can switch us
404 // out of the editing state.
405 // This MUST come before the updateItem call below, otherwise it will
406 // call cancelEdit(), resulting in both commit and cancel events being
407 // fired (as identified in RT-29650)
408 super.commitEdit(newValue);
409
410 // update the item within this cell, so that it represents the new value
411 if (treeItem != null) {
412 treeItem.setValue(newValue);
413 updateTreeItem(treeItem);
414 updateItem(newValue, false);
415 }
416
417 if (tree != null) {
418 // reset the editing item in the TreetView
419 tree.edit(null);
420
421 // request focus back onto the tree, only if the current focus
422 // owner has the tree as a parent (otherwise the user might have
423 // clicked out of the tree entirely and given focus to something else.
424 // It would be rude of us to request it back again.
425 ControlUtils.requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(tree);
426 }
427 }
428
429 /** {@inheritDoc} */
430 @Override public void cancelEdit() {
431 if (! isEditing()) return;
432
433 TreeView<T> tree = getTreeView();
434
435 super.cancelEdit();
436
437 if (tree != null) {
438 // reset the editing index on the TreeView
439 if (updateEditingIndex) tree.edit(null);
440
441 // request focus back onto the tree, only if the current focus
442 // owner has the tree as a parent (otherwise the user might have
443 // clicked out of the tree entirely and given focus to something else.
444 // It would be rude of us to request it back again.
445 ControlUtils.requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(tree);
446
447 tree.fireEvent(new TreeView.EditEvent<T>(tree,
448 TreeView.<T>editCancelEvent(),
449 getTreeItem(),
450 getItem(),
451 null));
452 }
453 }
454
455 /** {@inheritDoc} */
456 @Override protected Skin<?> createDefaultSkin() {
457 return new TreeCellSkin<T>(this);
458 }
459
460 /***************************************************************************
461 * *
462 * Private Implementation *
463 * *
464 **************************************************************************/
465
466 /** {@inheritDoc} */
467 @Override void indexChanged(int oldIndex, int newIndex) {
468 super.indexChanged(oldIndex, newIndex);
469
470 // when the cell index changes, this may result in the cell
471 // changing state to be selected and/or focused.
472 if (isEditing() && newIndex == oldIndex) {
473 // no-op
474 // Fix for RT-31165 - if we (needlessly) update the index whilst the
475 // cell is being edited it will no longer be in an editing state.
476 // This means that in certain (common) circumstances that it will
477 // appear that a cell is uneditable as, despite being clicked, it
478 // will not change to the editing state as a layout of VirtualFlow
479 // is immediately invoked, which forces all cells to be updated.
480 } else {
481 updateItem(oldIndex);
482 updateSelection();
483 updateFocus();
484 }
485 }
486
487 private boolean isFirstRun = true;
488 private void updateItem(int oldIndex) {
489 TreeView<T> tv = getTreeView();
490 if (tv == null) return;
491
492 // Compute whether the index for this cell is for a real item
493 int index = getIndex();
494 boolean valid = index >=0 && index < tv.getExpandedItemCount();
495 final boolean isEmpty = isEmpty();
496 final TreeItem<T> oldTreeItem = getTreeItem();
497
498 // Cause the cell to update itself
499 outer: if (valid) {
500 // update the TreeCell state.
501 // get the new treeItem that is about to go in to the TreeCell
502 TreeItem<T> newTreeItem = tv.getTreeItem(index);
503 T newValue = newTreeItem == null ? null : newTreeItem.getValue();
504 T oldValue = oldTreeItem == null ? null : oldTreeItem.getValue();
505
547 }
548
549 boolean isSelected = sm.isSelected(getIndex());
550 if (isSelected() == isSelected) return;
551
552 updateSelected(isSelected);
553 }
554
555 private void updateFocus() {
556 if (getIndex() == -1 || getTreeView() == null) return;
557
558 FocusModel<TreeItem<T>> fm = getTreeView().getFocusModel();
559 if (fm == null) {
560 setFocused(false);
561 return;
562 }
563
564 setFocused(fm.isFocused(getIndex()));
565 }
566
567 private boolean updateEditingIndex = true;
568 private void updateEditing() {
569 final int index = getIndex();
570 final TreeView<T> tree = getTreeView();
571 final TreeItem<T> treeItem = getTreeItem();
572 final TreeItem<T> editItem = tree == null ? null : tree.getEditingItem();
573 final boolean editing = isEditing();
574
575 if (index == -1 || tree == null || treeItem == null) return;
576
577 final boolean match = treeItem.equals(editItem);
578
579 // If my tree item is the item being edited and I'm not currently in
580 // the edit mode, then I need to enter the edit mode
581 if (match && !editing) {
582 startEdit();
583 } else if (! match && editing) {
584 // If my tree item is not the one being edited then I need to cancel
585 // the edit. The tricky thing here is that as part of this call
586 // I cannot end up calling tree.edit(null) the way that the standard
587 // cancelEdit method would do. Yet, I need to call cancelEdit
588 // so that subclasses which override cancelEdit can execute. So,
589 // I have to use a kind of hacky flag workaround.
590 updateEditingIndex = false;
591 cancelEdit();
592 updateEditingIndex = true;
593 }
594 }
595
596
597
598 /***************************************************************************
599 * *
600 * Expert API *
601 * *
602 **************************************************************************/
603
604
605
606 /**
607 * Updates the TreeView associated with this TreeCell.
608 *
609 * @param tree The new TreeView that should be associated with this TreeCell.
610 * Note: This function is intended to be used by experts, primarily
611 * by those implementing new Skins. It is not common
612 * for developers or designers to access this function directly.
|
374 // by calling super.startEdit().
375 super.startEdit();
376
377 // Inform the TreeView of the edit starting.
378 if (tree != null) {
379 tree.fireEvent(new TreeView.EditEvent<T>(tree,
380 TreeView.<T>editStartEvent(),
381 getTreeItem(),
382 getItem(),
383 null));
384
385 tree.requestFocus();
386 }
387 }
388
389 /** {@inheritDoc} */
390 @Override public void commitEdit(T newValue) {
391 if (! isEditing()) return;
392 final TreeItem<T> treeItem = getTreeItem();
393 final TreeView<T> tree = getTreeView();
394
395 // inform parent classes of the commit, so that they can switch us
396 // out of the editing state.
397 // This MUST come before the updateItem call below, otherwise it will
398 // call cancelEdit(), resulting in both commit and cancel events being
399 // fired (as identified in RT-29650)
400 super.commitEdit(newValue);
401
402 if (tree != null) {
403 // Inform the TreeView of the edit being ready to be committed.
404 tree.fireEvent(new TreeView.EditEvent<T>(tree,
405 TreeView.<T>editCommitEvent(),
406 treeItem,
407 getItem(),
408 newValue));
409 }
410
411 // update the item within this cell, so that it represents the new value
412 if (treeItem != null) {
413 treeItem.setValue(newValue);
414 updateTreeItem(treeItem);
415 updateItem(newValue, false);
416 }
417
418 if (tree != null) {
419 // reset the editing item in the TreetView
420 tree.edit(null);
421
422 // request focus back onto the tree, only if the current focus
423 // owner has the tree as a parent (otherwise the user might have
424 // clicked out of the tree entirely and given focus to something else.
425 // It would be rude of us to request it back again.
426 ControlUtils.requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(tree);
427 }
428 }
429
430 /** {@inheritDoc} */
431 @Override public void cancelEdit() {
432 if (! isEditing()) return;
433
434 TreeView<T> tree = getTreeView();
435
436 super.cancelEdit();
437
438 if (tree != null) {
439 // reset the editing index on the TreeView
440 tree.edit(null);
441
442 // request focus back onto the tree, only if the current focus
443 // owner has the tree as a parent (otherwise the user might have
444 // clicked out of the tree entirely and given focus to something else.
445 // It would be rude of us to request it back again.
446 ControlUtils.requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(tree);
447
448 tree.fireEvent(new TreeView.EditEvent<T>(tree,
449 TreeView.<T>editCancelEvent(),
450 getTreeItem(),
451 getItem(),
452 null));
453 }
454 }
455
456 /** {@inheritDoc} */
457 @Override protected Skin<?> createDefaultSkin() {
458 return new TreeCellSkin<T>(this);
459 }
460
461 /***************************************************************************
462 * *
463 * Private Implementation *
464 * *
465 **************************************************************************/
466
467 /** {@inheritDoc} */
468 @Override void indexChanged(int oldIndex, int newIndex) {
469 super.indexChanged(oldIndex, newIndex);
470
471 // when the cell index changes, this may result in the cell
472 // changing state to be selected and/or focused.
473 if (isEditing()) {
474 // no-op
475 // Fix for RT-31165 - if we (needlessly) update the index whilst the
476 // cell is being edited it will no longer be in an editing state.
477 // This means that in certain (common) circumstances that it will
478 // appear that a cell is uneditable as, despite being clicked, it
479 // will not change to the editing state as a layout of VirtualFlow
480 // is immediately invoked, which forces all cells to be updated.
481 } else {
482 updateItem(oldIndex);
483 }
484
485 updateSelection();
486 updateFocus();
487 }
488
489 private boolean isFirstRun = true;
490 private void updateItem(int oldIndex) {
491 TreeView<T> tv = getTreeView();
492 if (tv == null) return;
493
494 // Compute whether the index for this cell is for a real item
495 int index = getIndex();
496 boolean valid = index >=0 && index < tv.getExpandedItemCount();
497 final boolean isEmpty = isEmpty();
498 final TreeItem<T> oldTreeItem = getTreeItem();
499
500 // Cause the cell to update itself
501 outer: if (valid) {
502 // update the TreeCell state.
503 // get the new treeItem that is about to go in to the TreeCell
504 TreeItem<T> newTreeItem = tv.getTreeItem(index);
505 T newValue = newTreeItem == null ? null : newTreeItem.getValue();
506 T oldValue = oldTreeItem == null ? null : oldTreeItem.getValue();
507
549 }
550
551 boolean isSelected = sm.isSelected(getIndex());
552 if (isSelected() == isSelected) return;
553
554 updateSelected(isSelected);
555 }
556
557 private void updateFocus() {
558 if (getIndex() == -1 || getTreeView() == null) return;
559
560 FocusModel<TreeItem<T>> fm = getTreeView().getFocusModel();
561 if (fm == null) {
562 setFocused(false);
563 return;
564 }
565
566 setFocused(fm.isFocused(getIndex()));
567 }
568
569 private void updateEditing() {
570 final int index = getIndex();
571 final TreeView<T> tree = getTreeView();
572 final TreeItem<T> treeItem = getTreeItem();
573 final TreeItem<T> editItem = tree == null ? null : tree.getEditingItem();
574 final boolean editing = isEditing();
575
576 if (index == -1 || tree == null || treeItem == null) return;
577
578 final boolean match = treeItem.equals(editItem);
579
580 // If my tree item is the item being edited and I'm not currently in
581 // the edit mode, then I need to enter the edit mode
582 if (match && !editing) {
583 startEdit();
584 } else if (! match && editing) {
585 attemptEditCommit();
586 }
587 }
588
589
590
591 /***************************************************************************
592 * *
593 * Expert API *
594 * *
595 **************************************************************************/
596
597
598
599 /**
600 * Updates the TreeView associated with this TreeCell.
601 *
602 * @param tree The new TreeView that should be associated with this TreeCell.
603 * Note: This function is intended to be used by experts, primarily
604 * by those implementing new Skins. It is not common
605 * for developers or designers to access this function directly.
|