Skip to content

Commit 37ca873

Browse files
authored
🎨 [Frontend] Enh: Multiselect data with Ctrl key (#7027)
1 parent 85c3281 commit 37ca873

File tree

3 files changed

+90
-56
lines changed

3 files changed

+90
-56
lines changed

services/static-webserver/client/source/class/osparc/file/FileLabelWithActions.js

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ qx.Class.define("osparc.file.FileLabelWithActions", {
4949

5050
const deleteBtn = this.getChildControl("delete-button");
5151
deleteBtn.addListener("execute", () => this.__deleteSelected(), this);
52+
53+
this.__selection = [];
5254
},
5355

5456
events: {
@@ -61,13 +63,12 @@ qx.Class.define("osparc.file.FileLabelWithActions", {
6163
init: false,
6264
nullable: false,
6365
event: "changeMultiSelect",
64-
apply: "__enableMultiSelection",
66+
apply: "__changeMultiSelection",
6567
},
6668
},
6769

6870
members: {
6971
__selection: null,
70-
__multiSelection: null,
7172

7273
_createChildControlImpl: function(id) {
7374
let control;
@@ -99,9 +100,10 @@ qx.Class.define("osparc.file.FileLabelWithActions", {
99100
return control || this.base(arguments, id);
100101
},
101102

102-
__enableMultiSelection: function() {
103-
this.resetItemSelected();
104-
this.__multiSelection = [];
103+
__changeMultiSelection: function() {
104+
if (this.__selection.length > 1) {
105+
this.resetSelection();
106+
}
105107
},
106108

107109
setItemSelected: function(selectedItem) {
@@ -111,25 +113,25 @@ qx.Class.define("osparc.file.FileLabelWithActions", {
111113
this.getChildControl("delete-button").setEnabled(isFile);
112114
const selectedLabel = this.getChildControl("selected-label");
113115
if (isFile) {
114-
this.__selection = selectedItem;
116+
this.__selection = [selectedItem];
115117
selectedLabel.set({
116118
value: selectedItem.getLabel(),
117119
toolTipText: selectedItem.getFileId()
118120
});
119121
} else {
120-
this.__selection = null;
122+
this.__selection = [];
121123
selectedLabel.set({
122124
value: "",
123125
toolTipText: ""
124126
});
125127
}
126128
} else {
127-
this.resetItemSelected();
129+
this.resetSelection();
128130
}
129131
},
130132

131133
setMultiItemSelected: function(multiSelectionData) {
132-
this.__multiSelection = multiSelectionData;
134+
this.__selection = multiSelectionData;
133135
if (multiSelectionData && multiSelectionData.length) {
134136
if (multiSelectionData.length === 1) {
135137
this.setItemSelected(multiSelectionData[0]);
@@ -140,34 +142,27 @@ qx.Class.define("osparc.file.FileLabelWithActions", {
140142
});
141143
}
142144
} else {
143-
this.resetItemSelected();
145+
this.resetSelection();
144146
}
145147
},
146148

147-
resetItemSelected: function() {
148-
this.__selection = null;
149-
this.__multiSelection = [];
149+
resetSelection: function() {
150+
this.__selection = [];
150151
this.getChildControl("download-button").setEnabled(false);
151152
this.getChildControl("delete-button").setEnabled(false);
152153
this.getChildControl("selected-label").resetValue();
153154
},
154155

155-
getItemSelected: function() {
156-
const selectedItem = this.__selection;
157-
if (selectedItem && osparc.file.FilesTree.isFile(selectedItem)) {
158-
return selectedItem;
159-
}
160-
return null;
161-
},
162-
163156
__retrieveURLAndDownloadSelected: function() {
164157
if (this.isMultiSelect()) {
165-
this.__multiSelection.forEach(selection => {
166-
this.__retrieveURLAndDownloadFile(selection);
158+
this.__selection.forEach(selection => {
159+
if (selection && osparc.file.FilesTree.isFile(selection)) {
160+
this.__retrieveURLAndDownloadFile(selection);
161+
}
167162
});
168-
} else {
169-
const selection = this.getItemSelected();
170-
if (selection) {
163+
} else if (this.__selection.length) {
164+
const selection = this.__selection[0];
165+
if (selection && osparc.file.FilesTree.isFile(selection)) {
171166
this.__retrieveURLAndDownloadFile(selection);
172167
}
173168
}
@@ -176,10 +171,12 @@ qx.Class.define("osparc.file.FileLabelWithActions", {
176171
__deleteSelected: function() {
177172
if (this.isMultiSelect()) {
178173
const requests = [];
179-
this.__multiSelection.forEach(selection => {
180-
const request = this.__deleteFile(selection);
181-
if (request) {
182-
requests.push(request);
174+
this.__selection.forEach(selection => {
175+
if (selection && osparc.file.FilesTree.isFile(selection)) {
176+
const request = this.__deleteFile(selection);
177+
if (request) {
178+
requests.push(request);
179+
}
183180
}
184181
});
185182
Promise.all(requests)
@@ -190,9 +187,9 @@ qx.Class.define("osparc.file.FileLabelWithActions", {
190187
}
191188
});
192189
requests
193-
} else {
194-
const selection = this.getItemSelected();
195-
if (selection) {
190+
} else if (this.__selection.length) {
191+
const selection = this.__selection[0];
192+
if (selection && osparc.file.FilesTree.isFile(selection)) {
196193
const request = this.__deleteFile(selection);
197194
if (request) {
198195
request

services/static-webserver/client/source/class/osparc/file/FolderContent.js

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ qx.Class.define("osparc.file.FolderContent", {
4747
init: false,
4848
nullable: false,
4949
event: "changeMultiSelect",
50-
apply: "__reloadFolderContent"
50+
apply: "__changeMultiSelect"
5151
},
5252
},
5353

@@ -227,26 +227,43 @@ qx.Class.define("osparc.file.FolderContent", {
227227
} else if (this.getMode() === "icons") {
228228
const iconsLayout = this.getChildControl("icons-layout");
229229
iconsLayout.removeAll();
230-
const iconsGroup = new qx.ui.form.RadioGroup().set({
231-
allowEmptySelection: true
232-
});
233230
entries.forEach(entry => {
234-
if (!this.isMultiSelect()) {
235-
iconsGroup.add(entry);
236-
}
237231
iconsLayout.add(entry);
238232
});
239233
}
240234
this.setSelection([this.getSelectables()[this.getMode() === "icons" ? 0 : 1]]);
241235
},
242236

243-
__itemTapped: function(entry, buttonSelected) {
237+
__changeMultiSelect: function() {
238+
if (this.getMode() === "icons" && this.getMultiSelect() === false) {
239+
const iconsLayout = this.getChildControl("icons-layout");
240+
const selectedButtons = iconsLayout.getChildren().filter(btn => btn.getValue());
241+
if (selectedButtons.length > 1) {
242+
// reset selection
243+
selectedButtons.forEach(btn => btn.setValue(false));
244+
}
245+
} else if (this.getMode() === "list") {
246+
const selectionModel = this.getChildControl("table").getSelectionModel();
247+
let selection = null;
248+
if (selectionModel.getSelectedCount() === 1) {
249+
// keep selection
250+
selection = selectionModel.getSelectedRanges()[0];
251+
}
252+
selectionModel.setSelectionMode(this.isMultiSelect() ?
253+
qx.ui.table.selection.Model.MULTIPLE_INTERVAL_SELECTION_TOGGLE :
254+
qx.ui.table.selection.Model.SINGLE_SELECTION
255+
);
256+
if (selection) {
257+
selectionModel.setSelectionInterval(selection.minIndex, selection.maxIndex);
258+
}
259+
}
260+
},
261+
262+
__selectionChanged: function(selection) {
244263
if (this.isMultiSelect()) {
245-
this.fireDataEvent("multiSelectionChanged", entry);
246-
} else if (buttonSelected === false) {
247-
this.fireDataEvent("selectionChanged", null);
264+
this.fireDataEvent("multiSelectionChanged", selection);
248265
} else {
249-
this.fireDataEvent("selectionChanged", entry);
266+
this.fireDataEvent("selectionChanged", (selection && selection.length) ? selection[0] : null);
250267
}
251268
},
252269

@@ -255,7 +272,10 @@ qx.Class.define("osparc.file.FolderContent", {
255272
},
256273

257274
__attachListenersToGridItem: function(gridItem) {
258-
gridItem.addListener("tap", () => {
275+
gridItem.addListener("tap", e => {
276+
if (e.getNativeEvent().ctrlKey) {
277+
this.setMultiSelect(true);
278+
}
259279
if (this.isMultiSelect()) {
260280
// pass all buttons that are selected
261281
const selectedFiles = [];
@@ -265,9 +285,14 @@ qx.Class.define("osparc.file.FolderContent", {
265285
selectedFiles.push(btn.entry);
266286
}
267287
});
268-
this.__itemTapped(selectedFiles, gridItem.getValue());
288+
this.__selectionChanged(selectedFiles);
269289
} else {
270-
this.__itemTapped(gridItem.entry, gridItem.getValue());
290+
// unselect the other items
291+
const iconsLayout = this.getChildControl("icons-layout");
292+
iconsLayout.getChildren().forEach(btn => {
293+
btn.setValue(btn === gridItem);
294+
});
295+
this.__selectionChanged(gridItem.getValue() ? [gridItem.entry] : null);
271296
}
272297
// folders can't be selected
273298
if (osparc.file.FilesTree.isDir(gridItem.entry)) {
@@ -281,11 +306,20 @@ qx.Class.define("osparc.file.FolderContent", {
281306

282307
__attachListenersToTableItem: function(table) {
283308
table.addListener("cellTap", e => {
284-
const selectedRow = e.getRow();
285-
const rowData = table.getTableModel().getRowData(selectedRow);
286-
if ("entry" in rowData) {
287-
this.__itemTapped(rowData.entry);
309+
if (e.getNativeEvent().ctrlKey) {
310+
this.setMultiSelect(true);
288311
}
312+
const selectedFiles = [];
313+
const selectionRanges = table.getSelectionModel().getSelectedRanges();
314+
selectionRanges.forEach(range => {
315+
for (let i=range.minIndex; i<=range.maxIndex; i++) {
316+
const row = table.getTableModel().getRowData(i);
317+
if (osparc.file.FilesTree.isFile(row.entry)) {
318+
selectedFiles.push(row.entry);
319+
}
320+
}
321+
});
322+
this.__selectionChanged(selectedFiles);
289323
}, this);
290324
table.addListener("cellDbltap", e => {
291325
const selectedRow = e.getRow();

services/static-webserver/client/source/class/osparc/file/FolderViewer.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,21 @@ qx.Class.define("osparc.file.FolderViewer", {
5252
this.bind("folder", folderContent, "folder");
5353

5454
if (allowMultiselection) {
55+
multiSelectButton.bind("value", folderContent, "multiSelect");
56+
folderContent.bind("multiSelect", multiSelectButton, "value");
5557
multiSelectButton.addListener("changeValue", e => {
56-
folderContent.setMultiSelect(e.getData());
5758
selectedFileLayout.setMultiSelect(e.getData());
5859
});
5960
}
6061
gridViewButton.addListener("execute", () => {
6162
folderContent.setMode("icons");
62-
selectedFileLayout.resetItemSelected();
63+
selectedFileLayout.resetSelection();
64+
multiSelectButton.setValue(false);
6365
});
6466
listViewButton.addListener("execute", () => {
6567
folderContent.setMode("list");
66-
selectedFileLayout.resetItemSelected();
68+
selectedFileLayout.resetSelection();
69+
multiSelectButton.setValue(false);
6770
});
6871

6972
folderContent.addListener("requestDatasetFiles", e => this.fireDataEvent("requestDatasetFiles", e.getData()));
@@ -176,7 +179,7 @@ qx.Class.define("osparc.file.FolderViewer", {
176179
},
177180

178181
__applyFolder: function() {
179-
this.getChildControl("selected-file-layout").resetItemSelected();
182+
this.getChildControl("selected-file-layout").resetSelection();
180183
}
181184
}
182185
});

0 commit comments

Comments
 (0)