Skip to content

Commit

Permalink
Expose some selection control to the api
Browse files Browse the repository at this point in the history
* add_selection_change_handler: allows to handle selection change events;
* select_cells: allows to programmatically change the selection;
  • Loading branch information
prusse-martin committed May 2, 2017
1 parent 8496fc6 commit 5d988d5
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 0 deletions.
27 changes: 27 additions & 0 deletions qmxgraph/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,22 @@ def set_visible(self, cell_id, visible):
"""
return self.call_api('setVisible', cell_id, visible)

def set_selected_cells(self, cell_ids):
"""
Select the cells with the given ids.
:param list[str] cell_ids:
"""
return self.call_api('setSelectedCells', cell_ids)

def get_selected_cells(self):
"""
Get the selected cells ids.
:rtype: list[str]
"""
return self.call_api('getSelectedCells')

def remove_cells(self, cell_ids):
"""
Remove cells from graph.
Expand Down Expand Up @@ -293,6 +309,17 @@ def on_cells_removed(self, handler):
"""
return self.call_api('onCellsRemoved', qmxgraph.js.Variable(handler))

def on_selection_changed(self, handler):
"""
Add function to handle selection change events in the graph.
:param handler: Name of signal bound to JavaScript by a bridge object
that is going to be used as callback to event. Receives an list of
str with selected cells ids as only argument.
"""
return self.call_api(
'onSelectionChanged', qmxgraph.js.Variable(handler))

def resize_container(self, width, height):
"""
Resizes the container of graph drawing widget.
Expand Down
57 changes: 57 additions & 0 deletions qmxgraph/page/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,41 @@ graphs.Api.prototype.setVisible = function setVisible (cellId, visible) {
}
};

/**
* Select the cells with the given ids.
*
* @param {number[]} cellIds An array with the ids of the cells to select.
*/
graphs.Api.prototype.setSelectedCells = function setSelectedCells (cellIds) {
"use strict";

var cellsToSelect = [];
var model = api._graphEditor.graph.getModel();
var cell = null;
for (var i = cellIds.length; i--;) {
cell = model.getCell(cellIds[i]);
cellsToSelect.push(cell)
}

var selectionModel = this._graphEditor.graph.getSelectionModel();
selectionModel.setCells(cellsToSelect);
};

/**
* Get the ids of the selected cells.
*/
graphs.Api.prototype.getSelectedCells = function getSelectedCells () {
"use strict";

var selectionModel = this._graphEditor.graph.getSelectionModel();
var cells = selectionModel.cells;
var cellIds = [];
for (var i = cells.length; i--;) {
cellIds.push(cells[i].getId())
}
return cellIds;
};

/**
* Groups the currently selected cells in graph.
*/
Expand Down Expand Up @@ -515,6 +550,28 @@ graphs.Api.prototype.onCellsAdded = function onCellsAdded (handler) {
graph.addListener(mxEvent.ADD_CELLS, addHandler);
};

/**
* Add function to handle selection change events in the graph.
*
* @param {function} handler Callback that handles event. Receives an array with the id of cells
* that are selected as only argument.
*/
graphs.Api.prototype.onSelectionChanged = function onSelectionChanged (handler) {
"use strict";

var selectionHandler = function(source, event) {
var selectedCells = source.cells;
var selectedCellsIds = [];
for (var i = selectedCells.length; i--;) {
selectedCellsIds.push(selectedCells[i].getId());
}
handler(selectedCellsIds);
};

var selectionModel = this._graphEditor.graph.getSelectionModel();
selectionModel.addListener(mxEvent.CHANGE, selectionHandler);
};


/**
* Register a handler to event when cells have their label changed.
Expand Down
8 changes: 8 additions & 0 deletions qmxgraph/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ def set_events_bridge(self, bridge):
self.api.on_cells_added('bridge_events_handler.on_cells_added')
self.api.on_cells_removed('bridge_events_handler.on_cells_removed')
self.api.on_label_changed('bridge_events_handler.on_label_changed')
self.api.on_selection_changed(
'bridge_events_handler.on_selection_changed')

def set_double_click_handler(self, handler):
"""
Expand Down Expand Up @@ -511,6 +513,12 @@ class EventsBridge(QObject):
# old_label: str
on_label_changed = pyqtSignal(
str, str, str, name='on_label_changed')
# JavaScript client code emits this signal when the current selection
# change.
# Arguments:
# cell_ids: str
on_selection_changed = pyqtSignal(
'QVariantList', name='on_selection_changed')


class _DoubleClickBridge(QObject):
Expand Down
54 changes: 54 additions & 0 deletions tests/test_js_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,60 @@ def test_set_double_click_handler(graph_cases):
[vertex_id]


def test_add_selection_change_handler(graph_cases):
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""

graph = graph_cases('2v_1e')
source, target = graph.get_vertices()
edge = graph.get_edge(source, target)

graph.selenium.execute_script(
'callback = function(cellIds) {'
' if (!window.__selectionChange__) {'
' window.__selectionChange__ = [];'
' }'
' window.__selectionChange__.push(cellIds);'
'}')
graph.eval_js_function(
'api.onSelectionChanged', qmxgraph.js.Variable('callback'))

# Select all cells.
actions = ActionChains(graph.selenium)
actions.key_down(Keys.CONTROL)
actions.click(source)
actions.click(target)
actions.click(edge)
actions.key_up(Keys.CONTROL)
actions.perform()

fired_selection_events = graph.selenium.execute_script(
'return window.__selectionChange__')
assert fired_selection_events == [
['2'],
['3', '2'],
['4', '3', '2'],
]

assert graph.eval_js_function('api.getSelectedCells') == ['4', '3', '2']

# Programmatically select one cell.
graph.eval_js_function('api.setSelectedCells', ['3'])
# Clear selection.
graph.eval_js_function('api.setSelectedCells', [])

fired_selection_events = graph.selenium.execute_script(
'return window.__selectionChange__')
assert fired_selection_events == [
['2'],
['3', '2'],
['4', '3', '2'],
['3'],
[],
]


def test_set_popup_menu_handler(graph_cases):
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
Expand Down
10 changes: 10 additions & 0 deletions tests/test_qt_js_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def test_events_bridge(graph, qtbot):
added = []
removed = []
labels = []
selections = []

def on_cells_added(cell_ids):
added.extend(cell_ids)
Expand All @@ -68,11 +69,20 @@ def on_label_changed(a, b, c):

events.on_label_changed.connect(on_label_changed)

def on_selection_changed(cells_ids):
selections.extend(cells_ids)

events.on_selection_changed.connect(on_selection_changed)

wait_until_loaded(graph, qtbot)

vertex_id = graph.api.insert_vertex(10, 10, 20, 20, 'test')
assert added == [vertex_id]

assert selections == []
eval_js(graph, "graphEditor.execute('selectVertices')")
assert selections == [vertex_id]

graph.api.set_label(vertex_id, 'TOTALLY NEW LABEL')
assert labels == [vertex_id, 'TOTALLY NEW LABEL', 'test']

Expand Down

0 comments on commit 5d988d5

Please sign in to comment.