Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,7 @@
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.ToolBar;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
Expand Down Expand Up @@ -479,6 +475,29 @@ public ToolBar getToolbar() {
return toolbar;
}

/**
* Event handler for when a file is being dragged into the application to open it.
*/
private void onDragOverFile(DragEvent e) {
final Dragboard db = e.getDragboard();
if (db.hasFiles()) // Allow any drag operation containing files
e.acceptTransferModes(TransferMode.MOVE);

e.consume();
}

/**
* See `onDragOverFile` - this is called when the drag item was released.
*/
private void onDragDroppedFile(DragEvent e) {
final Dragboard db = e.getDragboard();

this.openDroppedResources(db);

e.setDropCompleted(true);
e.consume();
}

private void startUI(final MementoTree memento, final JobMonitor monitor) throws Exception {
monitor.beginTask(Messages.MonitorTaskUi, 4);

Expand All @@ -487,6 +506,11 @@ private void startUI(final MementoTree memento, final JobMonitor monitor) throws
toolbar = createToolbar();
createTopResourcesMenu();

menuBar.setOnDragOver(this::onDragOverFile);
menuBar.setOnDragDropped(this::onDragDroppedFile);
toolbar.setOnDragOver(this::onDragOverFile);
toolbar.setOnDragDropped(this::onDragDroppedFile);

DockStage.configureStage(main_stage);
// Patch ID of main window
// (in case we ever need to identify the main window)
Expand Down Expand Up @@ -1153,6 +1177,25 @@ private AppResourceDescriptor findApplication(final URI resource, final boolean
return applications.get(options.indexOf(result.get()));
}

/**
* Callback to trigger the loading of dragged resources.
* For each file the "Choose editor" dialog is shown.
*/
public void openDroppedResources(final Dragboard db) {

if (!db.hasFiles())
return;

var files = db.getFiles(); // Copy, because the event is going to be gone

Platform.runLater(() -> {
// Run this delayed, closing the drag event first, such that the icon will disappear from the UI
for (File file : files) {
this.openResource(file.toURI(), true);
}
});
}

/**
* @param resource Resource received as command line argument
* @param prompt Prompt if there are multiple applications, or use first one?
Expand Down
41 changes: 28 additions & 13 deletions core/ui/src/main/java/org/phoebus/ui/docking/DockPane.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
import javafx.scene.control.SplitPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.*;
import org.phoebus.framework.jobs.JobManager;
import org.phoebus.ui.application.Messages;
import org.phoebus.ui.application.PhoebusApplication;
import org.phoebus.ui.dialog.DialogHelper;
import org.phoebus.ui.javafx.ImageCache;
import org.phoebus.ui.javafx.Styles;
Expand All @@ -46,15 +48,9 @@
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

/** Pane that contains {@link DockItem}s
Expand Down Expand Up @@ -643,7 +639,8 @@
*/
private void handleDragOver(final DragEvent event)
{
if (!isFixed() && DockItem.dragged_item.get() != null)
if (event.getDragboard().hasFiles() ||
!isFixed() && DockItem.dragged_item.get() != null)
{
event.acceptTransferModes(TransferMode.MOVE);

Expand Down Expand Up @@ -782,22 +779,34 @@
*/
private void handleDrop(final DragEvent event)
{
if (!event.getDragboard().hasContent(DockItem.DOCK_ITEM))
return;
boolean result = false;
if (event.getDragboard().hasContent(DockItem.DOCK_ITEM))
result = handleDropDockItem(event);
// else if (event.getDragboard().hasFiles())

Check warning on line 785 in core/ui/src/main/java/org/phoebus/ui/docking/DockPane.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This block of commented-out lines of code should be removed.

See more on https://sonarcloud.io/project/issues?id=ControlSystemStudio_phoebus&issues=AaFoF9kk8FWiLAGvHNCJ&open=AaFoF9kk8FWiLAGvHNCJ&pullRequest=3731
// result = handleDropFile(event);
Comment on lines +783 to +786

@RobertoRoos RobertoRoos Oct 23, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@georgweiss this would override the option of dragging a .bob file into an editor to embed it. How could I prioritize the embedding behavior over opening the file?

EDIT: I see this 'embed' d-n-d is done from WidgetTransfer.addDropSupport(), not from a DockPane subclass or something, that's a little tricky.
Can we find from this whether the dock contains an editor?


if (result) { // Only complete the drop event if a handler ended up handling it
event.setDropCompleted(true);
event.consume();
}
}

/** Open a drag-and-dropped dock item. */
private boolean handleDropDockItem(final DragEvent event)
{
// When the cursor is directly over a tab header, let DockItem's own
// handler on name_tab manage the swap/insert. Clean up the pane border
// since no further DockPane handler will run for this drop.
if (isOverTabNode(event))
{
clearDropZoneStyle();
active_drop_zone = DropZone.CENTER;
return;
return false;
}

final DockItem item = DockItem.dragged_item.getAndSet(null);
if (item == null)
return;
return false;

final DropZone zone = getDropZone(event.getX(), event.getY());
clearDropZoneStyle();
Expand All @@ -813,8 +822,14 @@
splitAndPlaceTabAsync(item, zone);
}

event.setDropCompleted(true);
event.consume();
return true;
}

/** Open a drag-and-dropped file item. */
private boolean handleDropFile(final DragEvent event)

Check warning on line 829 in core/ui/src/main/java/org/phoebus/ui/docking/DockPane.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused private "handleDropFile" method.

See more on https://sonarcloud.io/project/issues?id=ControlSystemStudio_phoebus&issues=AaFoF9kk8FWiLAGvHNCI&open=AaFoF9kk8FWiLAGvHNCI&pullRequest=3731
{
PhoebusApplication.INSTANCE.openDroppedResources(event.getDragboard());
return true;
}

/** When a tab moves to a different scene, ensure that scene has the same stylesheets. */
Expand Down