Home Forums FlexGantt Selecting the row when a user selects a timeline object

  • Author
    Posts
  • Brian
    Participant
    Post count: 21
    #12823 |

    Rows get highlighted when a user selects a tree node/row in the left hand side of the gantt chart. This highlights the entire row (including the timeline object), which makes it easy for the user to visual identify the contents of that line. Multiselect is also supported for tree nodes.

    We would like to have the entire row highlight when the user selects a timeline object. We would also like to support multiselect. I spent most of yesterday trying to accomplish this using TimelineObjectSelectionListener implements ITimelineObjectSelectionListener, which I have plugged into the layer container like this: getLayerContainer().getSelectionModel(customTimeLineLayer).addTimelineObjectSelectionModelListener(new TimelineObjectSelectionListener(this));

    While this seems to do much of what one might need, I am struggling with multiselect support and also having trouble clearing selections from here. First, I would be curious to know if this is the right approach, since I don’t see a way to recognize the events of having shift or control pushed, as one would have in a MouseEvent Listener. Your thoughts on conceptual approach here would be helpful.

    I can past some code here that represents what I am doing, though it is constantly changing in an effort to understand the behavior & make something that works. One of the problems is that there seems to be many ways to get the selection and to select/unselect.

    public class TimelineObjectSelectionListener implements ITimelineObjectSelectionListener {
    private static final Logger LOG = LogManager.getLogger(TimelineObjectSelectionListener.class);
    private final ScheduleGanttChart chart;
    
    public TimelineObjectSelectionListener(final ScheduleGanttChart chart) {
    this.chart = chart;
    }
    
    @Override
    public void valueChanged(final TimelineObjectSelectionEvent event) {
    LOG.debug("caught TLO selection event: {} has {} paths", event, event.getTimelineObjectPaths().size());
    
    //chart.getLayerContainer().getTimelineObjectLayer(chart.getCustomTimeLineLayer())
    
    final Object sourceObj = event.getSource();
    LOG.debug("timeline object select source({}): {}", sourceObj.getClass(), sourceObj);
    final DefaultTimelineObjectSelectionModel realSource = (DefaultTimelineObjectSelectionModel) sourceObj;
    
    final List paths = event.getTimelineObjectPaths();
    LOG.debug("{} entries to act on", paths.size());
    
    // handle user dding a selection
    if (ID.TIMELINE_OBJECTS_ADDED == event.getId()) {
    
    // get the selected TLOs
    final ITimelineObjectSelectionModel selectionModel = chart.getLayerContainer().getSelectionModel(chart.getCustomTimeLineLayer());
    final Iterator treePaths = selectionModel.getSelectionPaths();
    final List allPaths = new ArrayList<>();
    while (treePaths.hasNext()) {
    final TreePath tp = treePaths.next();
    LOG.debug("previously selected TLO path: {}", tp);
    allPaths.add(tp);
    }
    
    // ignore the current selection, since it is in the above list
    
    selectionModel.removeSelection(event.getTimelineObjectPaths()); ???
    realSource.clearSelection();
    selectionModel.clearSelection();
    chart.getTreeTable().clearSelection();
    
    TreePath[] treePathArray = new TreePath[allPaths.size()];
    treePathArray = allPaths.toArray(treePathArray);
    chart.getTreeTable().setSelectionPaths(treePathArray);
    
    // handle user removing a selection
    } else if (ID.TIMELINE_OBJECTS_REMOVED == event.getId()) {
    
    // get the path to the deleted guy
    TreePath tPath = null;
    for (final TimelineObjectPath path : paths) {
    tPath = path.getTreePath();
    }
    //
    
    // peek at what it thinks are the current selections
    final ITimelineObjectSelectionModel selectionModel = chart.getLayerContainer().getSelectionModel(chart.getCustomTimeLineLayer());
    final Iterator treePaths = selectionModel.getSelectionPaths();
    final List allPaths = new ArrayList<>();
    while (treePaths.hasNext()) {
    final TreePath tp = treePaths.next();
    LOG.debug("previously selected TLO path: {}", tp);
    if (!tp.equals(tPath)) {
    allPaths.add(tp);
    }
    }
    selectionModel.removeSelection(event.getTimelineObjectPaths());
    
    //realSource.clearSelection();
    //selectionModel.clearSelection();
    //chart.getTreeTable().clearSelection();
    // TreePath[] treePathArray = new TreePath[allPaths.size()];
    // treePathArray = allPaths.toArray(treePathArray);
    // chart.getTreeTable().setSelectionPaths(treePathArray);
    
    // // process 'all' the items we should remove
    // for (final TimelineObjectPath path : paths) {
    // final TreePath tPath = path.getTreePath();
    // LOG.debug("removing row selection by TLO selection: {}", tPath);
    // chart.getTreeTable().removeSelectionPath(tPath);
    //
    // //realSource.removeSelection(path); also infinite recursion
    // realSource.clearSelection(tPath); // seems to be no effect
    // //selectionModel.removeSelection(path); //causes infinite recursion
    // // could I resonably clear selections here?
    // }
    } else {
    LOG.warn("not sure what to do with TLO selection.");
    }
    LOG.debug("-------------------------");
    
    }
    
  • Brian
    Participant
    Post count: 21
    #12824 |

    I hate to have posted the above code, because it is a mess. However, in more reasonable times I have tried code that looked much like the below.
    public void valueChanged(final TimelineObjectSelectionEvent event) {
    final List paths = event.getTimelineObjectPaths();
    LOG.debug(“caught TLO selection event: {} has {} paths”, event, paths.size());
    //chart.getLayerContainer().getTimelineObjectLayer(chart.getCustomTimeLineLayer())

    final Object sourceObj = event.getSource();
    LOG.debug(“timeline object select source({}): {}”, sourceObj.getClass(), sourceObj);
    final DefaultTimelineObjectSelectionModel realSource = (DefaultTimelineObjectSelectionModel) sourceObj;

    // handle user dding a selection
    if (ID.TIMELINE_OBJECTS_ADDED == event.getId()) {

    for (final TimelineObjectPath path : paths) {
    final TreePath tp = path.getTreePath();
    chart.getTreeTable().setSelectionPath(tp);
    }
    Wanted to share what I had in the hopes that it gave an idea how I was thinking about the problem, so you could me moving in the right direction.

  • Dirk Lemmermann
    Keymaster
    Post count: 61
    #12825 |

    The code in the second posting looks fine to me. Given this code, what exactly is not working?

  • Brian
    Participant
    Post count: 21
    #12826 |

    That code works in some sense. It is OK when the user makes a single selection, but does not support multiselect.
    When I look at:
    final List paths = event.getTimelineObjectPaths();
    LOG.debug(“caught TLO selection event: {} has {} paths”, event, paths.size());
    I only ever see on path coming in. This could work out fine if I call
    chart.getTreeTable().addSelectionPath(tp);
    Rather than
    chart.getTreeTable().setSelectionPath(tp);

    Of course, making that change is not a big deal. The corresponding removal logic would need to be in place for the remove event. I;ve been through various forms of that logic too. I dont recall a situation where the simple code I posted above combined with a similar version for TIMELINE_OBJECTS_REMOVED has produced a functional model, certainly not for multiselect.

  • Brian
    Participant
    Post count: 21
    #12827 |

    Given what I said in the previous post about only getting one path at a time from
    event.getTimelineObjectPaths()

    I have found that I get all the selections if I call

    final ITimelineObjectSelectionModel selectionModel = chart.getLayerContainer().getSelectionModel(chart.getCustomTimeLineLayer());
    final Iterator treePaths = selectionModel.getSelectionPaths();

    Presumably I could iterate over this list and select all the corresponding nodes. But, I have not found a way to make this work. I;ve tried clearing first, then setting the selections to this list, as one example.

    • Dirk Lemmermann
      Keymaster
      Post count: 61
      #12830 |

      The approach you describe here is the approach that I would use to implement this functionality.

  • Brian
    Participant
    Post count: 21
    #12828 |

    I’ll also post this, which might help. to handle the TIMELINE_OBJECTS_REMOVED condition, I have code like follows. I guess this might do what it is supposed to be by unselecting the node. The problem is that it appears that the timeline object does not get unselected, so next call to the listener shows all the selections made over time. With that experience I wondered if the timeline object select should have been taken care of by the framework, if I needed to make another call (that does not just call back to the listener, causing an infinte loop), or what.

    } else if (ID.TIMELINE_OBJECTS_REMOVED == event.getId()) {

    for (final TimelineObjectPath path : paths) {
    final TreePath tp = path.getTreePath();
    chart.getTreeTable().removeSelectionPath(tp);
    // it is not safe to remove the TLO selection, b/c that just calls back to here and blows the stack
    LOG.debug(“removing row selection by TLO selection for path: {}”, path.toString());
    //LOG.debug(“setting row selection by TLO selection for treepath: {}”, tp);

    }

  • Brian
    Participant
    Post count: 21
    #12829 |

    i think I can simplify the LassoLayer.selectObjects() code, since I already know what is selected and know what layer I need to work with.
    But, it creates new timelineobjectpath, which is something I am not doing.
    Also, wondering if I need my listener to add a key listener to make multiselect possible. I wanted to think the event and model have everything I needed to know, but I’m still missing something.

You must be logged in to reply to this topic.